Date manipulation: Difference between revisions
(Removed Frink example. Will restore with better version later.) |
|||
Line 326: | Line 326: | ||
2009-03-08T12:30:00Z London |
2009-03-08T12:30:00Z London |
||
</lang> |
</lang> |
||
=={{header|Frink}}== |
|||
Frink parses a large number of date/time formats, has robust date/time math, and automatically converts between timezones. By default, output times are in the user's defined timezone. |
|||
<lang frink> |
|||
### MMM dd yyyy h:mma ### |
|||
d = parseDate["March 7 2009 7:30pm EST"] |
|||
println[d + 12 hours] |
|||
println[d + 12 hours -> Switzerland] |
|||
</lang> |
|||
Output is: |
|||
<pre> |
|||
AD 2009-03-08 AM 07:30:00.000 (Sun) Mountain Daylight Time |
|||
AD 2009-03-08 PM 02:30:00.000 (Sun) Central European Time |
|||
</pre> |
|||
=={{header|Go}}== |
=={{header|Go}}== |
Revision as of 03:48, 18 May 2011
You are encouraged to solve this task according to the task description, using any language you may know.
Given the date string "March 7 2009 7:30pm EST", output the time 12 hours later in any human-readable format.
As extra credit, display the resulting time in a time zone different from your own.
Ada
ignoring input timezone for now (it defaults to UTC). feel free to add it.
<lang Ada>with Ada.Calendar.Formatting; with Ada.Strings.Fixed; with Ada.Text_IO; procedure Add_Hours is
use type Ada.Calendar.Time;
Parse_Error : Exception;
function Date_Value (From : String) return Ada.Calendar.Time is use Ada.Strings.Fixed;
function Month_Value (From : String) return Ada.Calendar.Month_Number is begin if From = "January" then return 1; elsif From = "February" then return 2; elsif From = "March" then return 3; elsif From = "April" then return 4; elsif From = "May" then return 5; elsif From = "June" then return 6; elsif From = "July" then return 7; elsif From = "August" then return 8; elsif From = "September" then return 9; elsif From = "October" then return 10; elsif From = "November" then return 11; elsif From = "December" then return 12; else raise Parse_Error; end if; end Month_Value;
function Time_Value (From : String) return Ada.Calendar.Day_Duration is Colon_Index : Positive := Index (From, ":"); Hours : Ada.Calendar.Formatting.Hour_Number := Integer'Value (From (From'First .. Colon_Index - 1)); Minutes : Ada.Calendar.Formatting.Minute_Number := Integer'Value (From (Colon_Index + 1 .. Colon_Index + 2)); begin if From (From'Last - 1) = 'p' then Hours := Hours + 12; end if; return Ada.Calendar.Formatting.Seconds_Of (Hours, Minutes); end Time_Value;
Month_End : Natural := Index (From, " ", From'First); Day_End : Natural := Index (From, " ", Month_End + 1); Year_End : Natural := Index (From, " ", Day_End + 1); Time_End : Natural := Index (From, " ", Year_End + 1); The_Month : Ada.Calendar.Month_Number := Month_Value (From (From'First .. Month_End - 1)); The_Day : Ada.Calendar.Day_Number := Integer'Value (From (Month_End + 1 .. Day_End)); The_Year : Ada.Calendar.Year_Number := Integer'Value (From (Day_End + 1 .. Year_End)); The_Time : Ada.Calendar.Day_Duration := Time_Value (From (Year_End + 1 .. Time_End - 1)); begin -- ignore time zone (feel free to add) return Ada.Calendar.Time_Of (The_Year, The_Month, The_Day, The_Time); end Date_Value;
Given_String : String := "March 7 2009 7:30pm EST"; Offset : Duration := 12 * 60 * 60.0; -- seconds Date : Ada.Calendar.Time := Date_Value (Given_String) + Offset;
begin
Ada.Text_IO.Put_Line (Ada.Calendar.Formatting.Image (Date));
end Add_Hours;</lang>
Output (since input is assumed to be UTC, EST gives wrong time):
$ TZ=UTC ./add_hours 2009-03-08 07:30:00 $ TZ=EST ./add_hours 2009-03-08 12:30:00
AppleScript
AppleScript has a built-in date class and can coerce a string to a date automatically. It also has reserved constants such as hours
which are defined in the unit of seconds. There is no built-in support for time zones.
<lang AppleScript>set x to "March 7 2009 7:30pm EST"
return (date x) + 12 * hours</lang>
Result is: <lang AppleScript>date "Sunday, March 8, 2009 7:30:00 AM"</lang>
AutoHotkey
<lang autohotkey>DateString := "March 7 2009 7:30pm EST"
- split the given string with RegExMatch
Needle := "^(?P<mm>\S*) (?P<d>\S*) (?P<y>\S*) (?P<t>\S*) (?P<tz>\S*)$" RegExMatch(DateString, Needle, $)
- split the time with RegExMatch
Needle := "^(?P<h>\d+):(?P<min>\d+)(?P<xm>[amp]+)$" RegExMatch($t, Needle, $)
- convert am/pm to 24h format
$h += ($xm = "am") ? 0 : 12
- knitting YYYYMMDDHH24MI format
_YYYY := $y _MM := Get_MonthNr($mm) _DD := SubStr("00" $d, -1) ; last 2 chars _HH24 := SubStr("00" $h, -1) ; last 2 chars _MI := $min YYYYMMDDHH24MI := _YYYY _MM _DD _HH24 _MI
- add 12 hours as requested
EnvAdd, YYYYMMDDHH24MI, 12, Hours FormatTime, HumanReadable, %YYYYMMDDHH24MI%, d/MMM/yyyy HH:mm
- add 5 hours to convert to different timezone (GMT)
EnvAdd, YYYYMMDDHH24MI, 5, Hours FormatTime, HumanReadable_GMT, %YYYYMMDDHH24MI%, d/MMM/yyyy HH:mm
- output
MsgBox, % "Given: " DateString "`n`n"
. "12 hours later:`n" . "(" $tz "):`t" HumanReadable "h`n" . "(GMT):`t" HumanReadable_GMT "h`n"
- ---------------------------------------------------------------------------
Get_MonthNr(Month) { ; convert named month to 2-digit number
- ---------------------------------------------------------------------------
If (Month = "January") Result := "01" Else If (Month = "February") Result := "02" Else If (Month = "March") Result := "03" Else If (Month = "April") Result := "04" Else If (Month = "May") Result := "05" Else If (Month = "June") Result := "06" Else If (Month = "July") Result := "07" Else If (Month = "August") Result := "08" Else If (Month = "September") Result := "09" Else If (Month = "October") Result := "10" Else If (Month = "November") Result := "11" Else If (Month = "December") Result := "12" Return, Result
}</lang> Message box shows:
Given: March 7 2009 7:30pm EST 12 hours later: (EST): 8/Mar/2009 07:30h (GMT): 8/Mar/2009 12:30h
C
<lang c>#include <stdio.h>
- include <stdlib.h>
- include <time.h>
int main() {
struct tm ts; time_t t; const char *d = "March 7 2009 7:30pm EST"; strptime(d, "%B %d %Y %I:%M%p %Z", &ts); /* ts.tm_hour += 12; instead of t += 12*60*60 works too. */ t = mktime(&ts); t += 12*60*60; printf("%s", ctime(&t));
return EXIT_SUCCESS;
}</lang>
Note: ctime
treats the date as local, so that it is like the timezone information were discarded (to see the passage to daylight saving time I must change the date into March 28... no matter the timezone specified)
C#
<lang csharp>class Program {
static void Main(string[] args) { CultureInfo ci=CultureInfo.CreateSpecificCulture("en-US"); string dateString = "March 7 2009 7:30pm EST"; string format = "MMMM d yyyy h:mmtt z"; DateTime myDateTime = DateTime.ParseExact(dateString.Replace("EST","+6"),format,ci) ; DateTime newDateTime = myDateTime.AddHours(12).AddDays(1) ; Console.WriteLine(newDateTime.ToString(format).Replace("-5","EST")); //probably not the best way to do this
Console.ReadLine(); }
}</lang>
C++
compiled with g++ -lboost_date_time <lang cpp>#include <string>
- include <iostream>
- include <boost/date_time/local_time/local_time.hpp>
- include <sstream>
- include <boost/date_time/gregorian/gregorian.hpp>
- include <vector>
- include <boost/algorithm/string.hpp>
- include <cstdlib>
- include <locale>
int main( ) {
std::string datestring ("March 7 2009 7:30pm EST" ) ; //we must first parse the date string into a date , a time and a time //zone part , to take account of present restrictions in the input facets //of the Boost::DateTime library used for this example std::vector<std::string> elements ; //parsing the date string boost::split( elements , datestring , boost::is_any_of( " " ) ) ; std::string datepart = elements[ 0 ] + " " + "0" + elements[ 1 ] + " " + elements[ 2 ] ; //we must add 0 to avoid trouble with the boost::date_input format strings std::string timepart = elements[ 3 ] ; std::string timezone = elements[ 4 ] ; const char meridians[ ] = { 'a' , 'p' } ; //we have to find out if the time is am or pm, to change the hours appropriately std::string::size_type found = timepart.find_first_of( meridians, 0 ) ; std::string twelve_hour ( timepart.substr( found , 1 ) ) ; timepart = timepart.substr( 0 , found ) ; //we chop off am or pm elements.clear( ) ; boost::split( elements , timepart , boost::is_any_of ( ":" ) ) ; long hour = std::atol( (elements.begin( ))->c_str( ) ) ;// hours in the string if ( twelve_hour == "p" ) //it's post meridian, we're converting to 24-hour-clock hour += 12 ; long minute = std::atol( ( elements.begin( ) + 1)->c_str( ) ) ; boost::local_time::tz_database tz_db ; tz_db.load_from_file( "/home/ulrich/internetpages/date_time_zonespec.csv" ) ; //according to the time zone database, this corresponds to one possible EST time zone boost::local_time::time_zone_ptr dyc = tz_db.time_zone_from_region( "America/New_York" ) ; //this is the string input format to initialize the date field boost::gregorian::date_input_facet *f = new boost::gregorian::date_input_facet( "%B %d %Y" ) ; std::stringstream ss ; ss << datepart ; ss.imbue( std::locale( std::locale::classic( ) , f ) ) ; boost::gregorian::date d ; ss >> d ; boost::posix_time::time_duration td ( hour , minute , 0 ) ; //that's how we initialize the New York local time , by using date and adding //time duration with values coming from parsed date input string boost::local_time::local_date_time lt ( d , td , dyc ,
boost::local_time::local_date_time::NOT_DATE_TIME_ON_ERROR ) ;
std::cout << "local time: " << lt << '\n' ; ss.str( "" ) ; ss << lt ; //we have to add 12 hours, so a new time duration object is created boost::posix_time::time_duration td2 (12 , 0 , 0 , 0 ) ; boost::local_time::local_date_time ltlater = lt + td2 ; //local time 12 hours later boost::gregorian::date_facet *f2 = new boost::gregorian::date_facet( "%B %d %Y , %R %Z" ) ; std::cout.imbue( std::locale( std::locale::classic( ) , f2 ) ) ; std::cout << "12 hours after " << ss.str( ) << " it is " << ltlater << " !\n" ; //what's New York time in the Berlin time zone ? boost::local_time::time_zone_ptr bt = tz_db.time_zone_from_region( "Europe/Berlin" ) ; std::cout.imbue( std::locale( "de_DE.UTF-8" ) ) ; //choose the output forman appropriate for the time zone std::cout << "This corresponds to " << ltlater.local_time_in( bt ) << " in Berlin!\n" ; return 0 ;
} </lang> this produces the following output:
local time: 2009-Mar-07 19:30:00 EST 12 hours after 2009-Mar-07 19:30:00 EST it is 2009-Mar-08 08:30:00 EDT ! This corresponds to 2009-Mär-08 13:30:00 CET in Berlin!
Clojure
<lang Clojure>(import java.util.Date java.text.SimpleDateFormat)
(defn time+12 [s]
(let [sdf (SimpleDateFormat. "MMMM d yyyy h:mma zzz")] (-> (.parse sdf s)
(.getTime ,) (+ , 43200000) long (Date. ,) (->> , (.format sdf ,)))))</lang>
F#
The .NET framework does not support parsing of time zone identifiers like "EST". We have to use time zone offsets like "-5".
<lang fsharp>open System
let main() =
let est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time") let date = DateTime.Parse("March 7 2009 7:30pm -5" ) let date_est = TimeZoneInfo.ConvertTime( date, est) let date2 = date.AddHours(12.0) let date2_est = TimeZoneInfo.ConvertTime( date2, est) Console.WriteLine( "Original date in local time : {0}", date ) Console.WriteLine( "Original date in EST : {0}", date_est ) Console.WriteLine( "12 hours later in local time: {0}", date2 ) Console.WriteLine( "12 hours later in EST : {0}", date2_est )
main()</lang>
Output (depends on locale settings):
Original date in local time : 08.03.2009 01:30:00 Original date in EST : 07.03.2009 19:30:00 12 hours later in local time: 08.03.2009 13:30:00 12 hours later in EST : 08.03.2009 07:30:00
Fantom
In the expression "d + 12hr", the "12hr" defines an instance of the Duration class, interpreting the duration in nanoseconds.
<lang fantom> fansh> d := DateTime.fromLocale("March 7 2009 7:30pm EST", "MMMM D YYYY h:mmaa zzz") fansh> d 2009-03-07T19:30:00-05:00 EST fansh> d + 12hr 2009-03-08T07:30:00-05:00 EST fansh> (d+12hr).toTimeZone(TimeZone("London")) // the extra credit! 2009-03-08T12:30:00Z London </lang>
Go
Library parser uses an easy-to-read prototype. Library formatter offers only two choices for time zone, local and UTC. Otherwise the library formatter has lots of flexibility, but code here just takes the default, "UnixDate" format. <lang go>package main
import (
"fmt" "time"
)
const taskDate = "March 7 2009 7:30pm EST" const taskFormat = "January 2 2006 3:04pm MST"
func main() {
fmt.Println("Input:", taskDate) t, err := time.Parse(taskFormat, taskDate) if err != nil { fmt.Println(err) return } t2 := t.Seconds() + 12*60*60 fmt.Println("+12 hrs, local:", time.SecondsToLocalTime(t2)) fmt.Println("+12 hrs, UTC: ", time.SecondsToUTC(t2))
}</lang> Output:
Input: March 7 2009 7:30pm EST +12 hrs, local: Sun Mar 8 08:30:00 EDT 2009 +12 hrs, UTC: Sun Mar 8 12:30:00 UTC 2009
Haskell
<lang haskell>import Data.Time.Clock.POSIX import Data.Time.Format import System.Locale
main = print t2
where t1 = readTime defaultTimeLocale "%B %e %Y %l:%M%P %Z" "March 7 2009 7:30pm EST" t2 = posixSecondsToUTCTime $ 12*60*60 + utcTimeToPOSIXSeconds t1</lang>
HicEst
<lang hicest>
CHARACTER date="March 7 2009 7:30pm EST", am_pm, result*20
EDIT(Text=date, Parse=cMonth, GetPosition=next) month = 1 + EDIT(Text='January,February,March,April,May,June,July,August,September,October,November,December', Right=cMonth, Count=',' ) READ(Text=date(next:)) day, year, hour, minute, am_pm hour = hour + 12*(am_pm == 'p') TIME(MOnth=month, Day=day, Year=year, Hour=hour, MInute=minute, TO, Excel=xls_day) WRITE(Text=result, Format="UWWW CCYY-MM-DD HH:mm") xls_day + 0.5 ! result = "Sun 2009-03-08 07:30" END
</lang>
Icon and Unicon
This uses the datetime procedures from the Icon Programming Library. Several supplemental procedures were needed to normalize the date format (as the one used in the task isn't fully compatible with the library), and to better handle time zones (as the library routines don't handle part hour time zones).
<lang Icon>link datetime
procedure main() write("input = ",s := "March 7 2009 7:30pm EST" ) write("+12 hours = ",SecToTZDateLine(s := TZDateLineToSec(s) + 12*3600,"EST")) write(" = ",SecToTZDateLine(s,"UTC")) write(" = ",SecToTZDateLine(s,"NST")) end
procedure SecToTZDateLine(s,tz) #: returns dateline + time zone given seconds return NormalizedDate(SecToDateLine(s+\(_TZdata("table")[\tz|"UTC"]))||" "|| tz) end
procedure TZDateLineToSec(s) #: returns seconds given dateline (and time zone)
return ( NormalizedDate(s) ? ( d := tab(find("am"|"pm")+2),tab(many('\t ,')), tz := \_TZdata("table")[tab(0)] ), DateLineToSec(d) - tz)
end
procedure NormalizedDate(s) #: returns a consistent dateline static D,M initial {
D := ["Saturday","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday"] M := ["January","February","March","April","May","June", "July","August","September","October","November","December"] }
map(s) ? { # parse and build consistent dateline
ds := 1(x := !D, =map(x)) | "" # Weekday ds ||:= 1(", ", tab(many('\t ,')|&pos)) ds ||:= 1(x := !M, =map(x)) | fail # Month ds ||:= 1(" ", tab(many('\t ,')|&pos)) ds ||:= tab(many(&digits)) | fail # day ds ||:= 1(", ", tab(many('\t ,'))) | fail ds ||:= tab(many(&digits)) | fail # year ds ||:= 1(" ", tab(many('\t ,'))) | fail ds ||:= tab(many(&digits))||(=":"||tab(many(&digits))|&null) | fail # time ds ||:= 1(" ", tab(many('\t ,')|&pos)) ds ||:= =("am"|"pm") | fail # halfday ds ||:= 1(" ", tab(many('\t ,')|&pos)) tz := map(=!_TZdata("list"),&lcase,&ucase) }
if ds[1] == "," then
ds := SecToDateLine(DateLineToSec("Sunday"||ds)) # get IPL to fix weekday
return ds ||:= " " || \tz|"UTC" end
procedure _TZdata(x) #: internal return TZ data (demo version incomplete) static TZ,AZ initial {
TZ := table() AZ := [] "UTC/0;ACDT/+10.5;CET/1;EST/-5;NPT/+5.75;NST/-3.5;PST/-8;" ? while ( a := tab(find("/")), move(1), o := tab(find(";")), move(1) ) do { TZ[map(a)] := TZ[a] := integer(3600*o) put(AZ,a,map(a)) } every TZ[&null|""] := TZ["UTC"] }
return case x of { "list" : AZ ; "table" : TZ } end</lang>
datetime provides SecToDateLine, and DateLineToSec these convert between Icon's &dateline format and seconds from a configurable base date (which defaults to the normal 1970 epoch).
Output:
input = March 7 2009 7:30pm EST +12 hours = Sunday, March 8, 2009 7:30 am EST = Sunday, March 8, 2009 12:30 pm UTC = Sunday, March 8, 2009 9:00 am NST
Java
<lang Java>import java.util.Date; import java.text.SimpleDateFormat; public class DateManip{
public static void main(String[] args) throws Exception{
String dateStr = "March 7 2009 7:30pm EST";
SimpleDateFormat sdf = new SimpleDateFormat("MMMM d yyyy h:mma zzz");
Date date = sdf.parse(dateStr);
date.setTime(date.getTime() + 43200000l);
System.out.println(sdf.format(date));
}
}</lang> Output:
March 8 2009 8:30AM EDT
or using System.out.println(date); as the last line:
Sun Mar 08 08:30:00 EDT 2009
Lua
The following solution is quite ugly, but unfortunately there is not anything like 'strptime'-function in Lua. <lang lua> str = string.lower( "March 7 2009 7:30pm EST" )
month = string.match( str, "%a+" ) if month == "january" then month = 1 elseif month == "february" then month = 2 elseif month == "march" then month = 3 elseif month == "april" then month = 4 elseif month == "may" then month = 5 elseif month == "june" then month = 6 elseif month == "july" then month = 7 elseif month == "august" then month = 8 elseif month == "september" then month = 9 elseif month == "october" then month = 10 elseif month == "november" then month = 11 elseif month == "december" then month = 12 end
strproc = string.gmatch( str, "%d+" ) day = strproc() year = strproc() hour = strproc() min = strproc()
if string.find( str, "pm" ) then hour = hour + 12 end
print( os.date( "%c", os.time{ year=year, month=month, day=day, hour=hour, min=min, sec=0 } + 12 * 3600 ) ) </lang> Output:
Sun Mar 8 07:30:00 2009
Mathematica
<lang Mathematica>dstr = "March 7 2009 7:30pm EST"; DateString[DatePlus[dstr, {12, "Hour"}], {"DayName", " ", "MonthName", " ", "Day", " ", "Year", " ", "Hour24", ":", "Minute", "AMPM"}]</lang>
Perl
We use Mountain Daylight Time for output.
<lang perl>use DateTime; use DateTime::Format::Strptime 'strptime'; use feature 'say';
my $input = 'March 7 2009 7:30pm EST'; $input =~ s{EST}{America/New_York};
say strptime('%b %d %Y %I:%M%p %O', $input)
->add(hours => 12) ->set_time_zone('America/Edmonton') ->format_cldr('MMMM d yyyy h:mma zzz');</lang>
If we're given an ambiguous timezone like 'EST' for input, we can handle this by changing it to the unambiguous Olson timezone id. This ensures daylight savings is correctly handled (which is especially tricky here, since March 7/8 is the DST rollover, and times jump ahead skipping an hour)
Output:
March 8 2009 6:30AM MDT
PHP
<lang php><?php $time = new DateTime('March 7 2009 7:30pm EST'); $time->modify('+12 hours'); echo $time->format('c'); ?></lang>
PicoLisp
<lang PicoLisp>(de timePlus12 (Str)
(use (@Mon @Day @Year @Time @Zone) (and (match '(@Mon " " @Day " " @Year " " @Time " " @Zone) (chop Str) ) (setq @Mon (index (pack @Mon) *MonFmt)) (setq @Day (format @Day)) (setq @Year (format @Year)) (setq @Time (case (tail 2 @Time) (("a" "m") ($tim (head -2 @Time))) (("p" "m") (+ `(time 12 0) ($tim (head -2 @Time)))) (T ($tim @Time)) ) ) (let? Date (date @Year @Mon @Day) (when (>= (inc '@Time `(time 12 0)) 86400) (dec '@Time 86400) (inc 'Date) ) (pack (dat$ Date "-") " " (tim$ @Time T) " " @Zone) ) ) ) )</lang>
PL/I
<lang PL/I> /* The PL/I date functions handle dates and time in 49 */ /* different formats, but not that particular one. For any of the */ /* standard formats, the following date manipulation will add */ /* 12 hours to the current date/time. */
seconds = SECS(DATETIME()); seconds = seconds + 12*60*60; put list (SECSTODATE(secs)); </lang>
Python
I don't do anything with timezone here, but it is possible.
<lang python>import datetime
def mt(): datime1="March 7 2009 7:30pm EST" formatting = "%B %d %Y %I:%M%p " datime2 = datime1[:-3] # format can't handle "EST" for some reason tdelta = datetime.timedelta(hours=12) # twelve hours.. s3 = datetime.datetime.strptime(datime2, formatting) datime2 = s3+tdelta print datime2.strftime("%B %d %Y %I:%M%p %Z") + datime1[-3:]
mt()</lang>
R
<lang R>time <- strptime("March 7 2009 7:30pm EST", "%B %d %Y %I:%M%p %Z") # "2009-03-07 19:30:00" isotime <- ISOdatetime(1900 + time$year, time$mon, time$mday,
time$hour, time$min, time$sec, "EST") # "2009-02-07 19:30:00 EST"
twelvehourslater <- isotime + 12 * 60 * 60 # "2009-02-08 07:30:00 EST" timeincentraleurope <- format(isotime, tz="CET", usetz=TRUE) #"2009-02-08 01:30:00 CET"</lang>
REBOL
<lang REBOL>REBOL [ Title: "Date Manipulation" Author: oofoe Date: 2009-12-06 URL: http://rosettacode.org/wiki/Date_Manipulation ]
- Only North American zones here -- feel free to extend for your area.
zones: [ NST -3:30 NDT -2:30 AST -4:00 ADT -3:00 EST -5:00 EDT -4:00 CST -6:00 CDT -5:00 MST -7:00 MDT -6:00 PST -8:00 PDT -7:00 AKST -9:00 AKDT -8:00 HAST -10:00 HADT -9:00]
read-time: func [ text /local m d y t z ][ parse load text [ set m word! (m: index? find system/locale/months to-string m) set d integer! set y integer! set t time! set tz word!] to-date reduce [y m d t zones/:tz] ]
print 12:00 + read-time "March 7 2009 7:30pm EST" </lang>
Output:
8-Mar-2009/7:30-5:00
Ruby
The Time
package in the standard library adds a parse
method to the core Time
class.
<lang ruby>require 'time' d = "March 7 2009 7:30pm EST" t = Time.parse(d) puts t.rfc2822 puts t.zone
new = t + 12*3600 puts new.rfc2822 puts new.zone
- another timezone
require 'rubygems' require 'active_support' zone = ActiveSupport::TimeZone['Beijing'] remote = zone.at(new)
- or, remote = new.in_time_zone('Beijing')
puts remote.rfc2822 puts remote.zone</lang> outputs
Sat, 07 Mar 2009 19:30:00 -0500 EST Sun, 08 Mar 2009 08:30:00 -0400 EDT Sun, 08 Mar 2009 20:30:00 +0800 CST
Using ActiveSupport, we can add 12 hours with any of: <lang ruby>new = t + 12.hours new = t.in(12.hours) new = t.advance(:hours => 12)</lang>
Smalltalk
The aim of the class DateTimeTZ is to provide the ability to understand time with "meridian" (PM/AM, even though no checks are done to assure coherency of the format) and to handle timezones despite the locale (which anyway is gently "ignored", or rather unknown in the format of letters, to Date), providing a proper set of informations to the method readFromWithMeridian:andTimeZone:
.
The aDict
argument must be a dictionary where keys are the abbreviated timezone code (e.g. EST), and values are three-elements array: difference between the timezone and GMT (as Duration), the DateTime when there's passage between using or not using the daylight saving time (year is ignored), and the "direction" (as Duration) of the change. All data must be filled by hand... As example I've put EST (and there's no way to represent the "new" date and time correctly with the new EDT timezone).
The code also fails when adding a duration that "jumps" beyond two DST changes (e.g from EST to EDT and EST again); (it could be partially fixed by considering intervals instead of single date, and adding a fourth element to link to the "new" timezone abbreviation)
<lang smalltalk>DateTime extend [
setYear: aNum [ year := aNum ]
].
Object subclass: DateTimeTZ [
|dateAndTime timeZoneDST timeZoneName timeZoneVar|
DateTimeTZ class >> new [ ^(super basicNew) ]
DateTimeTZ class >> readFromWithMeridian: aStream andTimeZone: aDict [ |me| me := self new. ^ me initWithMeridian: aStream andTimeZone: aDict ]
initWithMeridian: aStream andTimeZone: aDict [ |s| dateAndTime := DateTime readFrom: aStream copy. s := aStream collection asString. s =~ '[pP][mM]' ifMatched: [ :m | dateAndTime := dateAndTime + (Duration days: 0 hours: 12 minutes: 0 seconds: 0) ]. aDict keysAndValuesDo: [ :k :v | s =~ k ifMatched: [ :x | dateAndTime := dateAndTime setOffset: (v at: 1).
timeZoneDST := (v at: 2) setOffset: (v at: 1). timeZoneVar := (v at: 3). timeZoneDST setYear: (self year). "ignore the year"
timeZoneName := k ] ]. ^ self ]
setYear: aNum [ dateAndTime setYear: aNum ] year [ ^ dateAndTime year ]
timeZoneName [ ^timeZoneName ]
+ aDuration [ |n| n := dateAndTime + aDuration. (n > timeZoneDST) ifTrue: [ n := n + timeZoneVar ]. ^ (self copy dateTime: n) ]
dateTime [ ^dateAndTime ] dateTime: aDT [ dateAndTime := aDT ]
].</lang>
Usage example (note: the code is rather rigid, so not all operations possible on DateTime are possible on DateTimeTZ).
<lang smalltalk>|s abbrDict dt|
s := 'March 7 2009 7:30pm EST'.
"Build a abbreviation -> offset for timezones (example)" abbrDict := Dictionary new.
abbrDict at: 'EST'
put: { (Duration days: 0 hours: -5 minutes: 0 seconds: 0). (DateTime year: 2009 month: 3 day: 8 hour: 2 minute: 0 second: 0).
(Duration days: 0 hours: 1 minutes: 0 seconds: 0) }.
dt := DateTimeTZ readFromWithMeridian: (s readStream) andTimeZone: abbrDict.
dt := dt + (Duration days: 0 hours: 12 minutes: 0 seconds: 0).
"let's print it" ('%1 %2 %3 %4:%5%6 %7' % {
(dt dateTime) monthName asString. (dt dateTime) day. (dt dateTime) year. (dt dateTime) hour12. (dt dateTime) minute. (dt dateTime) meridianAbbreviation asString. dt timeZoneName.
}) displayNl.
(dt dateTime) asUTC displayNl.</lang>
Output example (note that EST should be EDT):
March 8 2009 8:30AM EST 2009-03-08T13:30:00+00:00
Tcl
<lang tcl>set date "March 7 2009 7:30pm EST" set epoch [clock scan $date -format "%B %d %Y %I:%M%p %z"] set later [clock add $epoch 12 hours] puts [clock format $later] ;# Sun Mar 08 08:30:00 EDT 2009 puts [clock format $later -timezone :Asia/Shanghai] ;# Sun Mar 08 20:30:00 CST 2009</lang>
Note the transition into daylight savings time in the interval (in the Eastern timezone).
UNIX Shell
requires GNU date <lang bash>date -d 'March 7 2009 7:30pm EST +12 hours'</lang>
- Programming Tasks
- Text processing
- Ada
- Ada examples needing attention
- Examples needing attention
- AppleScript
- AutoHotkey
- C
- C sharp
- C++
- Boost
- Clojure
- F Sharp
- Fantom
- Go
- Haskell
- HicEst
- Icon
- Unicon
- Icon Programming Library
- Java
- Lua
- Mathematica
- Perl
- PHP
- PicoLisp
- PL/I
- Python
- R
- REBOL
- Ruby
- RubyGems
- ActiveSupport
- Smalltalk
- Tcl
- UNIX Shell
- PARI/GP/Omit
- Date and time