Monday, January 4, 2010

Supporting Timezones in Google App Engine Pt. 3 - Your Timezone Aware App

I am covering how I added Timezone support to my web application My Web Brain in a series of posts.  Hopefully someone will find the discussion useful or even better contribute ways to achieve the same effect.
In Part 0 of the series I described how, out of the box, python Dates and Datetimes could be timezone aware, but how the Google App Engine converts these to UTC when persisted and returns naive values when they are retrieved. In Part 1 I looked at the facilities available in pytz to provide timezone information. In Part 2 I showed a simple custom property which ensured the datastore much more explicitly used UTC. In this last part of the series I hope to show you can input, output and list timezones to take you the last mile toward a timezone aware application.

Note: I've scaled this post back, mostly since I was being tardy in completing it and also with the realisation that the extra detail I might add would be too specific to my recent experience.

Converting datetimes on input

Sometimes your application will accept as input a user provided date or datetime. In a timezone aware application the working assumption must be that this date is in the user's local timezone. It therefore needs to be converted to UTC for storage.

A handy feature of the datastore datetime property is that as long as your datetime is marked with a specific timezone, the datastore will automatically convert the value to UTC when it is persisted. Once you have parsed your datetime from the input, simply assign the user's timezone before persisting. For example:

user_datetime = parse_datetime(self.request.get('user_date'))
my_model_entity.user_datetime = user_datetime.replace(tzinfo=pytz.timezone(user_timezone_name))
my_model_entity.put()


Of course if you are accepting input from the system time, you do not need to assign a timezone, it is already in UTC, even thought it is a naive datetime.

my_model_entity.log_datetime = datetime.datetime.now()
my_model_entity.put()



Converting dates (only) on input

This is pretty straightforward. There is a situation though where your application would normally only care about dates, but because of your support for timezones you are persisting datetime objects. The user would select a date, say the 10th of January of this year, but when persisting this as a datetime you have a crucial decision to make - what time on the 10th of January should you store? In all situations you will want to set this time prior to converting to UTC. The decision about which time to use is non-trivial since your application will likely want to use the information in the effective manner.  The answer will vary from application to application, but a couple of examples might illustrate the point.

In my application My Web Brain, the user can enter a Due Date for a next action that they define. In this application we will be asking one critical question on a regular basis concerning the due date - is the next action overdue? Something is overdue when the due date has past, not during that date, so My Web Brain adds 23 hours and 59 minutes to the due date. This gets converted to UTC when it is persisted, so any Next Action which is overdue can be queried easily by using a condition comparing the due date with the system time.

To provide some contrast, My Web Brain also supports Someday Maybe items with 'tickle dates'. A tickle date is provided by the user to indicate when they should be reminded. In this situation the application will want to find all Someday Maybe items that are due to be 'tickled', and this should include any such item on the same local date the user entered. Therefore, we do not add any amount of time when combining to create a tickle date. Again, since this date was converted to UTC prior to persisted this query is easy for the application to do without knowing the user's local timezone.

Other situations will require other time offsets. Perhaps if a user's work day ends at 5pm, the due date should reflect this. The common thread is that right time offset will depend on the application. Once you have a determined this, the code is easy:


due_date = parse_date (self.request.get('user_date'))
due_datetime = due_date.combine(datetime.time(hours=17))
next_action_entity.duedate = due_datetime.replace(tzinfo=pytz.timezone(user_timezone_name))
next_action_entity.put()


Converting datetimes on output

At the other end of your application you will want to show the user dates and datetimes in their local time. From the datastore you will retrieve datetimes in UTC - these values need to be converted to the user's timezone.

local_duedate = next_action_entity.duedate.astimezone(pytz.timezone(user_timezone_name))

There is nothing overwhelmingly difficult about the above line of code, but you could be forgiven for wondering where in your application it should go. You need to decide if the derived local time of the data should belong to the model, view or controller part of your application:

  • If make the conversion to local time a part of the view, you need to share the user's timezone information with the view. The view is often implemented in a templating language like Django templates which out of the box does not provide the capability to do this as a view operation. The best way to use the view in this way would be to define a custom tag for the templating engine, which is not overly difficult. 
  • You might make the conversion to local time a responsibility of the controller, which after all can access different parts of the model to both find the user's timezone preference and the data with the times to be converted. On the downside, converting the date times and providing them separately (or mixed in to the data) is messy and, in my opinion, increases the coupling between controller and view more than necessary.
  • Making the conversion to local time a responsibility of the model is perhaps the easiest approach in the short term. Simple add a method to provide the local time to your entity's class. This has the benefit of making your entities less anemic, but introduces the requirement for one piece of your model to know the user's timezone, which might belong in somewhere else in the model entirely. It can also lead to timezone conversion code duplication across your model. 

For My Web Brain I have at the moment chosen to invest the responsibility of converting times to the user's local time to the model, but I wonder if view-based solution would provide more long-term benefits to performance and model design.

Who knew the single line of code converting a time between timezones could require such thinking? Maybe it is only me who can make it so.

Other Questions

There are some other points to cover about using making your application timezone aware. How do you generate a list of timezones for the user to pick from? I have a solution for this, but it isn't elegant. Another good question is how the best way would be to guess the correct timezone for a user. Those who have seen my frequent calls to pytz.timezone() may wonder what the performance penalty is (from what I have read, it is worth looking into).

But- This entry is getting long and I might leave these topics for another occasion. Remember that if you have something to add or something to ask, you are welcome to go ahead and do so. I still have significant learning to do in this area and I will keep you posted when I do.

23 comments:

  1. Hey there, thanks for the great post! I'm trying to figure out how to get the user's timezone programmatically (user_timezone_name).

    Have any suggestions?

    ReplyDelete
  2. Hi Anekdotz Team - This is something I am interested in too. From my reading there does not appear to be a perfect answer. You can guess the user's timezone using either javascript (to get the browser time and the UTC offset) or via IP Geo Location. Either way you can not be completely sure it is correct. Let me know if you find out anything useful. Thanks for your comment.

    PS. I thought this blog post and comments were useful:
    http://mces.blogspot.com/2008/10/timezone-in-http-header.html

    ReplyDelete
  3. Wow what a Great Information about World Day its very nice informative post. thanks for the post. Get online Reviews For Your Business

    ReplyDelete
  4. Keep on putting up! You completely match our expectation and the variety of our information. technowalla

    ReplyDelete
  5. All in all, what is the correct method to building the endeavor apps? https://iphoneappdevelopmentcompany.com/ In spite of the fact that the correct approach relies upon the circumstance and methodology, here are some broad rules to construct portable apps for business the correct way.

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Android 3 Apps is other free utility to make an android application for your Android contraptions of your decision. It has three straightforward strides to make Android application.
    https://appcloner.app
    https://appcloner.net

    ReplyDelete
  8. In short, a mobile application will assist you in the promotion and improvement of your business. It will also keep your brand ahead in this race of technology.Mobile app development

    ReplyDelete
  9. Free Android App Maker is a standout amongst other free utility to make an android application. Bulk SMS Service Provider in Sharjah UAE

    ReplyDelete
  10. One challenge for enterprise mobile app developers is to ensure the app actually performs well. Other than performance, the app should be bug free and able to operate at minimum battery power.Mobile App development

    ReplyDelete
  11. A mobile application is the best marketing and communication tool for any business/company in an inexpensive way. Keeping in mind, the importance of mobile application and its usability, you can either choose Android or iOS.Smart AudioBook Player Download

    ReplyDelete
  12. As an app developer, you must implement a complete mobile application testing strategy to release a bug-free application. However, you can either test the app manually or automate the testing efforts.https://thefrisky.com/how-the-spy-apps-can-help-you-to-keep-a-check-on-the-dishonest-employees/

    ReplyDelete
  13. Applications that are produced for Android stage are Android application. Every application when created conveys a wide range of records and envelopes inside it..itools crack

    ReplyDelete
  14. A backlink is a link created when one website links to another. Backlinks are important to SEO & impact for higher ranking. In my 7+ years seo Career i see, without backlinks a website doesn't rank higher on google SERP.

    Get Your 300+ High Quality DoFollow Backlinks Here!

    Order Now with Full Confidence & 100% satisfaction.

    ReplyDelete
  15. With Brandsoo, it’s never been easier or more convenient to shop high quality domain names and professional logos that’ll instantly give your brand a leg up and resonate with your audience! With many brandable domain names different domain sellers all competing for your business, you need to know where your business and brand will see.

    ReplyDelete
  16. Forex Signals, MT4 and MT5 Indicators, Strategies, Expert Advisors, Forex News, Technical Analysis and Trade Updates in the FOREX IN WORLD

    Forex Signals Forex Strategies Forex Indicators Forex News Forex World

    ReplyDelete
  17. Thanks for sharing. Nếu cần vận chuyển hàng đi campuchia thì a/c liên hệ bên mình nhé. Hotline: 0903751981

    ReplyDelete
  18. Keeping up with Brilyent Kelly. Get Exlcusive offers and see the latest Music and news & Follow me on instragram Celebrity.

    ReplyDelete
  19. Eco technology is the best environmental consulting firm in Bangladesh. To solve all kind of support.

    ReplyDelete

  20. Nurse Practitioner interview questions often focus on clinical knowledge, patient care experience, and critical thinking abilities, aiming to assess candidates' readiness for advanced practice roles. These questions may also explore candidates' communication skills, professionalism, and commitment to continuing education and professional development.

    click here

    ReplyDelete