When you're building a website, you'll inevitably come into contact with dates and times. When was that submitted? Show only posts created after this time. How long has that user been registered?
In this lesson we'll briefly cover how Ruby handles dates and times. It's good to have a framework in your head for how timestamps are treated but you don't need to necessarily remember every method used to modify or print them.
All languages have conventions for how they keep track of dates and times and, of course, Ruby is no different... just a bit easier than the rest. In general, computers keep track of time in terms of seconds since a specified point in time. Someone decided a long time ago that Time shall begin at midnight on January 1st, 1970, and so that's typically the "0th" second.
Ruby uses the
Time class to let you work with dates and times.
Time has some handy methods to investigate specific parts of the timestamp (like what day of the week it is) and to allow you to display them in a user-friendly fashion (like "Monday January 10th 1999").
To Get Current Time you just create a new
Time object with no parameters or use
Time.now, which is the same thing:
> Time.new #=> 2013-07-10 17:04:10 -0700 > Time.now #=>2013-07-10 17:04:11 -0700
Time gives you some handy methods to ask it questions. Almost all of them are very intuitive, so the general rule is "if you think the method should exist, it probably does":
> my_time = Time.now #=> 2013-07-10 17:04:10 -0700 > my_time.year #=> 2013 > my_time.month #=> 7 > my_time.day #=> 10 > my_time.wday # the day of the week, starting Sunday #=> 0 > my_time.hour #=> 17 > my_time.min #=> 4 > my_time.sec #=> 10
Time also takes inputs if you want to create a specific time, from year to time zone:
Time.new(year, month, day, hour, min, sec, utc_offset)
Note that the time zone offset is in seconds, so add or subtract 3600 per hour offset from UTC.
> Time.new(2001,2,14) #=> 2001-02-14 00:00:00 -0800 > Time.new(2001,2,14,6,30,26,-3600) #=> 2001-02-14 06:30:26 -0100
You can add and subtract times just like they were numbers (because, remember, they basically are... just the number of seconds since 1970):
> vday = Time.new(2001,2,14) # Valentine's Day! #=> 2001-02-14 00:00:00 -0800 > vday+3600 # 1 hour's worth of seconds #=> 2001-02-14 01:00:00 -0800 > xmas = Time.new(2013,12,25) #=> 2013-12-25 00:00:00 -0700 # Xmas! > ( xmas - Time.now )/60/60/24.to_i #=> 167 # That's too long...
What if you want to display a date in a pretty way, like on your website or for your user's benefit? There are a couple of baked in methods and then a "build-your-own-adventure" way to specify:
> nownow = Time.now #=> 2013-07-10 17:37:27 -0700 > nownow.ctime # a standard display type #=> "Wed Jul 10 17:38:10 2013" > nownow.utc # Remove the time zone #=> 2013-07-11 00:38:10 UTC > nownow.strftime("%Y-%m-%d %H:%M:%S") #=> "2013-07-11 00:38:10"
Wait, what were all those
%Y characters? They just tell the
strftime method what components of the
Time to output and how you'd like them formatted. There's a long list of them back at the TutorialsPoint site.
You don't need to remember them since you can just google for them when you decide to output a string, but know that they give you the flexibility to output a date or time in pretty much any way you could imagine.
# Don't memorize! For future reference... %a # The abbreviated weekday name (Sun). %A # The full weekday name (Sunday). %b # The abbreviated month name (Jan). %B # The full month name (January). %c # The preferred local date and time representation. %d # Day of the month (01 to 31). %H # Hour of the day, 24-hour clock (00 to 23). %I # Hour of the day, 12-hour clock (01 to 12). %j # Day of the year (001 to 366). %m # Month of the year (01 to 12). %M # Minute of the hour (00 to 59). %p # Meridian indicator (AM or PM). %S # Second of the minute (00 to 60). %U # Week number of the current year, starting with the first Sunday as the first day of the first week (00 to 53). %W # Week number of the current year, starting with the first Monday as the first day of the first week (00 to 53). %w # Day of the week (Sunday is 0, 0 to 6). %x # Preferred representation for the date alone, no time. %X # Preferred representation for the time alone, no date. %y # Year without a century (00 to 99). %Y # Year with century. %Z # Time zone name. %% # Literal % character.
What's that trailing
2001-02-14 00:00:00 -0800? It's because that time was created on our local system, which is many hours "earlier" in the day from the Coordinated Universal Time (called UTC... no, it doesn't match up but here's why) which is used by computers around the world as the standard benchmark time. That way, two computers communicating about times will always be talking about the same exact one and not have to worry about time zones.
I prefer to think of UTC as "Universal Time Code" because reasons. UTC is the new GMT... Greenwich Mean Time. You'll start thinking of things in terms of "how many hours away am I from England?" when you run into time zone bugs somewhere down the road.
Back to the point, the
-0800 above says that we created a new time for midnight on Valentine's Day but only from the perspective of someone on the West Coast of the USA... it was really 8am in Greenwich, England and according to every other computer in the world. You'll forget this stuff until you need it and that's fine.
localtime to display the Time object in whatever your local system time is (if it was created in UTC it will be different). Note that it actually modifies the Time object so it will continue displaying in that time zone!
> t = Time.new(2012,2,14,6,30,26,-3600) #=> 2012-02-14 06:30:26 -0100 > t.localtime #=> 2012-02-13 23:30:26 -0800 # US West Coast Time > t #=> 2012-02-13 23:30:26 -0800 # Stuck in local for now > t.strftime("%A %B %d, %Y at %H:%M %p in %Z") #=> "Monday February 13, 2012 at 23:30 PM in PST"