Thursday, October 22, 2009

Recipe 3.8. Checking Whether Daylight Saving Time Is in Effect










Recipe 3.8. Checking Whether Daylight Saving Time Is in Effect





Problem


You want to see whether the current time in your locale is normal time or Daylight Saving/Summer Time.




Solution


Create a Time object and check its
isdst
method:



Time.local(2006, 1, 1) # => Sun Jan 01 00:00:00 EST 2006
Time.local(2006, 1, 1).
isdst # => false
Time.local(2006, 10, 1) # => Sun Oct 01 00:00:00 EDT 2006
Time.local(2006, 10, 1).isdst # => true





Discussion


Time objects representing UTC times will always return false when isdst is called, because UTC is the same year-round. Other Time objects will consult the daylight saving time rules for the time locale used to create the Time object. This is usually the sysem locale on the computer you used to create it: see Recipe 3.7 for information on changing it. The following code demonstrates some of the rules pertaining to Daylight Saving Time across the United States:



eastern = Time.local(2006, 10, 1) # => Sun Oct 01 00:00:00 EDT 2006
eastern.isdst # => true

ENV['TZ'] = 'US/Pacific'
pacific = Time.local(2006, 10, 1) # => Sun Oct 01 00:00:00 PDT 2006
pacific.isdst # => true

# Except for the Navajo Nation, Arizona doesn't use Daylight Saving Time.
ENV['TZ'] = 'America/Phoenix'
arizona = Time.local(2006, 10, 1) # => Sun Oct 01 00:00:00 MST 2006
arizona.isdst # => false

# Finally, restore the original time zone.
ENV['TZ'] = nil



The C library on which Ruby's Time class is based handles the complex rules for Daylight Saving Time across the history of a particular time zone or locale. For instance,



Daylight Saving Time was mandated across the U.S. in 1918, but abandoned in most locales shortly afterwards. The "zoneinfo" file used by the C library contains this information, along with many other rules:



# Daylight saving first took effect on March 31, 1918.
Time.local(1918, 3, 31).isdst # => false
Time.local(1918, 4, 1).isdst # => true
Time.local(1919, 4, 1).isdst # => true

# The federal law was repealed later in 1919, but some places
# continued to use
Daylight Saving Time.
ENV['TZ'] = 'US/Pacific'
Time.local(1920, 4, 1) # => Thu Apr 01 00:00:00 PST 1920

ENV['TZ'] = nil
Time.local(1920, 4, 1) # => Thu Apr 01 00:00:00 EDT 1920

# Daylight Saving Time was reintroduced during the Second World War.
Time.local(1942,2,9) # => Mon Feb 09 00:00:00 EST 1942
Time.local(1942,2,10) # => Tue Feb 10 00:00:00 EWT 1942
# EWT stands for "Eastern War Time"



A U.S. law passed in 2005 expands Daylight Saving Time into March and November, beginning in 2007. Depending on how old your zoneinfo file is, Time objects you create for dates in 2007 and beyond might or might not reflect the new law.



Time.local(2007, 3, 13) # => Tue Mar 13 00:00:00 EDT 2007
# Your computer may incorrectly claim this time is EST.



This illustrates a general point. There's nothing your elected officials love more than passing laws, so you shouldn't rely on isdst to be accurate for any Time objects that represent times a year or more into the future. When that time actually comes around, Daylight Saving Time might obey different rules in your locale.


The Date class isn't based on the C library, and knows nothing about time zones or locales, so it also knows nothing about Daylight Saving Time.




See Also


  • Recipe 3.7, "
    Converting Between Time Zones"

  • Information on the "zoneinfo" database (http://www.twinsun.com/tz/tz-link.htm)













No comments: