Problem with time stamp
One of the long neglected problems with our microblog applications is the display of daytime and date.
Until now, we have used Python's own way of rendering the time object in our user and post objects, but this is not a good solution.
Consider such an example. I am writing this article, this is December 31 3:54. My time zone is PST (or you are more accustomed to: UTC-8). Running in the Python interpreter, I get the following output:
>>> from datetime import datetime
>>> now = DateTime.Now ()
>>> print
now 2012-12-31 15:54:42.915204
>>> now = Datetime.utcnow ()
>>> print now
2012-12-31 23:55:13.635874
Where I am, the Now () method returns the correct time, but the time returned by the Today () call is the UTC unit.
So, which is better to use?
If we use now (), the timestamp in all databases will be the same as the local time the server is running, which will create some problems.
For example, if one day we need to place the server somewhere else (not in a time zone), the time in the database needs to be updated to match the new location before restarting the server.
There will be more important issues. Users in different time zones will find it difficult to know when to send a message, and if the user sees a PST time zone, it is difficult to know when the message was sent, which requires the user to adjust accordingly.
Obviously this is not a good choice, which is why we use the UTC time zone to save the timestamp when we create the database.
The problem with the mobile server was resolved when the standardized timestamp was UTC. But he couldn't solve the second problem, with data and time being presented to users in different parts of the world using UTC.
Suppose a user sends an e-mail message in the PST time Zone 3 o'clock in the afternoon, which immediately appears in front of him, 11:00pm, or more specifically (23:00).
The purpose of my writing this article is to make our users no longer confused by the display of data and time.
Use a specific time stamp
The usual solution is for each user to convert from UTC to local time. This requires us to change dynamically so that the UTC of the database is aligned with it.
But how do we know where the user is?
Many sites have a settings page that sets their time zone. This requires us to add a new page, and provide a Drop-down box on the form to allow the user to select the time zone, the first time the user login needs to set the time zone, and as part of the registration.
This is a normal workaround, but this is a bit cumbersome for users, who need to enter a message that they have configured in the operating system. So if we can grab the time zone set on the user's computer, the problem will become more efficient.
For security reasons, browsers do not allow us to access the user's operating system for information. Even if it does, we need to know where to get the time zone in Windows,linux,mac,ios,android, which does not include other non-mainstream operating systems.
Gets the user's time zone in the browser, and then through the standard JavaScript API. In the Web 2.0 world, users allow JavaScript to execute (few sites do not use JavaScript), so it is possible to get user time zones via JavaScript.
We use JavaScript to configure the available time zones in two ways:
Old-fashioned way: When a user logs on to the server for the first time, let the browser send time zone information to us in some way. This can be invoked via Ajax or, more simply, through the meta-refresh tag. Once the server knows the time zone information, it can save it in the user session, and then adjust the time display for all pages.
The new approach: do not change anything on the server side, but still send a UTC timestamp to the client browser. The work of converting UTC to local time is performed through JavaScript on the client.
Both methods are valid, but the second one is more advantageous. The browser can perform the best time conversion according to the local configuration of the system. Like the morning/afternoon vs 24-hour system, day/month/year vs month/day/year and other cultural formats that browsers can access, the server is not necessarily.
If that's not enough, there's a bigger advantage to the new pie, and someone else has done it for us (Moment.js is coming)!
Moment.js Introduction
Moment.js is a small, free, open source JavaScript library that promotes dates and events to another level. It provides all the time and date formats imaginable, and here are some.
To use Moment.js in our application, we need to write a lost JavaScript code in our template file. Let's start by using ISO 8601 time to create a moment object. For example: Create a Moment object from the UTC time of the python example above, like this:
Moment ("2012-12-31t23:55:13 Z")
Once an object is created, it can be transformed into a string of various format types. For example, the time to convert a gray-long time display to the Local system:
Moment ("2012-12-31t23:55:13 Z"). Format (' llll ');
The following is the transition time display:
Tuesday, January 1 2013 7:55 AM
Here are a few more examples of converting the same timestamp into different formats:
This class library supports the conversion options more than that. In addition to format (), it provides Fromnow () and calendar () For more friendly timestamp conversions:
Note that in all of the above examples, the server converts the same UTC time, and your own local browser converts different times.
Finally, we'll make up for some of the missing JavaScript tips, and it's obvious in the page that the code actually returned the string type by moment. The simplest way to accomplish this is to use the Document.Write method of javascript:
<script>
document.write (Moment ("2012-12-31t23:55:13 Z"). Format (' llll ');
</script>
Using JavaScript's document.write is a simple and straightforward way to generate part of the HTML code, but note that there are some limitations to this approach. The most needed point is that the Document.Write method can only be used when the document is loaded, and when the document is loaded, it cannot modify the document. The result of this limitation is that the solution will fail when the data is loaded through Ajax.
Integrated Moment.js
Here we need to do a little something to add moment.js to our microblog.
First, we need to download moment.min.js this library into the/app/static/js folder so that it can serve as a static file for the client.
Then we add the reference to this library (moment.min.js) in our template file (fileapp/templates/base.html):
<script src= "/static/js/moment.min.js" ></script>
Now we can add <script> tags to the template file to show the time stamp we want. But we wanted to replace this method, so we added a layer of packaging to moment.min.js to better call it from the template. This saves us the time to modify the timestamp code in the future, because we just need to change it in one place.
Our packaging is a very simple Python class (fileapp/momentjs.py):
From JINJA2 import Markup
class Momentjs:
def __init__ (self, timestamp):
Self.timestamp = Timestamp
def render (self, format): Return
Markup ("<script>\ndocument.write" (Moment (\ "%s\").%s);\n</script> " % (Self.timestamp.strftime ("%y-%m-%dt%h:%m:%s Z"), format))
def format (self, FMT): Return
Self.render (" Format (\ "%s\") "% fmt"
def calendar (self): return
self.render ("Calendar ()")
def Fromnow (self):
Return Self.render ("Fromnow ()")
Note that the Render method here does not return a string type directly but returns a markup object provided by our template engine Jinja2. The reason for this is that JINJA2 will escape all strings by default, for example, our <script> tags cannot be uploaded to the client, but will be replaced with <script> ("<" ">" These symbols are escaped, translator note). Therefore, wrapping these strings with the markup object tells JINJA2 that these strings cannot be escaped.
Now that we have a wrapper, we need to connect through JINJA2 so that our template can call it (fileapp/__init__.py):
From Momentjs import Momentjs
app.jinja_env.globals[' momentjs ' = Momentjs
So JINJA2 will expose our class as a global variable to all the templates.
Now we are ready to start modifying our template. There are two places in our application to display dates and events. One is on the user Properties page and we show the "last seen" time. For this timestamp we will use the calendar () method to convert (fileapp/templates/user.html):
{% if User.last_seen%}
<p><em>last seen: {{Momentjs (user.last_seen). Calendar ()}}</em></p>
{% endif%}
The second place is a child template for post, which is called by the Index,user and search pages. Here we use the Fromnow () method to convert, because how long post is created is more important than what time it was created. To extract post time from the conversion to the subpage, we only need to change one place to affect all post times that need to be converted (fileapp/templates/post.html):
<p><a href= "{{url_for (' user ', nickname = Post.author.nickname)}}" >{{post.author.nickname}}</a> Said {{Momentjs (post.timestamp). Fromnow ()}}:</p>
<p><strong>{{post.body}}</strong> </p>
As these templates change, we solve all the timestamp problems. We do not need to modify the server-side code alone!
Conclusion
Unconsciously, today, by doing some changes to the client's time and date configuration, it has made a significant step towards making micro blogs more popular with many countries.
In the next installment of this series, we're going to make micro blogs support multiple languages (internationalization), making it more popular for users in different countries.
At the same time, there is a download link for an integrated moment.js application:
Download Microblog-0.13.zip.