Date manipulation

From Rosetta Code
Revision as of 14:04, 13 December 2013 by rosettacode>Bengt (Added Erlang)
Task
Date manipulation
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

The Ada way: long, type-based, clear, reliable. Most of the code consists of declarations. Only standard libraries are required.

<lang Ada>with Ada.Calendar; with Ada.Calendar.Formatting; with Ada.Calendar.Time_Zones; with Ada.Integer_Text_IO; with Ada.Text_IO;

procedure Date_Manipulation is

  type Month_Name_T is
    (January, February, March, April, May, June,
     July, August, September, October, November, December);
  type Time_Zone_Name_T is (EST, Lisbon);
  type Period_T is (AM, PM);
  package TZ renames Ada.Calendar.Time_Zones;
  use type TZ.Time_Offset;
  Time_Zone_Offset : array (Time_Zone_Name_T) of TZ.Time_Offset :=
    (EST => -5 * 60,
     Lisbon => 0);

  Period_Offset : array (Period_T) of Natural :=
    (AM => 0,
     PM => 12);
  package Month_Name_IO is
     new Ada.Text_IO.Enumeration_IO (Month_Name_T);
  package Time_Zone_Name_IO is
     new Ada.Text_IO.Enumeration_IO (Time_Zone_Name_T);
  package Period_IO is
     new Ada.Text_IO.Enumeration_IO (Period_T);
  package Std renames Ada.Calendar;
  use type Std.Time;
  package Fmt renames Std.Formatting;
  function To_Number (Name : Month_Name_T) return Std.Month_Number is
  begin
     return Std.Month_Number (Month_Name_T'Pos (Name) + 1);
  end;
  function To_Time (S : String) return Std.Time is
     Month : Month_Name_T;
     Day : Std.Day_Number;
     Year : Std.Year_Number;
     Hour : Fmt.Hour_Number;
     Minute : Fmt.Minute_Number;
     Period : Period_T;
     Time_Zone : Time_Zone_Name_T;
     I : Natural;
  begin
     Month_Name_IO.Get
       (From => S, Item => Month, Last => I);
     Ada.Integer_Text_IO.Get
       (From => S (I + 1 .. S'Last), Item => Day, Last => I);
     Ada.Integer_Text_IO.Get
       (From => S (I + 1 .. S'Last), Item => Year, Last => I);
     Ada.Integer_Text_IO.Get
       (From => S (I + 1 .. S'Last), Item => Hour, Last => I);
     Ada.Integer_Text_IO.Get
       (From => S (I + 2 .. S'Last), Item => Minute, Last => I);
        --  here we start 2 chars down to skip the ':'
     Period_IO.Get
       (From => S (I + 1 .. S'Last), Item => Period, Last => I);
     Time_Zone_Name_IO.Get
       (From => S (I + 1 .. S'Last), Item => Time_Zone, Last => I);
     return Fmt.Time_Of
       (Year => Year,
        Month => To_Number (Month),
        Day => Day,
        Hour => Hour + Period_Offset (Period),
        Minute => Minute,
        Second => 0,
        Time_Zone => Time_Zone_Offset (Time_Zone));
  end;
  
  function Img
    (Date : Std.Time; Zone : Time_Zone_Name_T) return String is
  begin
     return
        Fmt.Image (Date => Date, Time_Zone => Time_Zone_Offset (Zone)) &
        " " & Time_Zone_Name_T'Image (Zone);
  end;
  T1, T2 : Std.Time;
  use Ada.Text_IO;

begin

  T1 := To_Time ("March 7 2009 7:30pm EST");
  T2 := T1 + 12.0 * 60.0 * 60.0; 
  Put_Line ("T1 => " & Img (T1, EST) & " = " & Img (T1, Lisbon));
  Put_Line ("T2 => " & Img (T2, EST) & " = " & Img (T2, Lisbon));

end;</lang>

Result:

T1 => 2009-03-07 19:30:00 EST = 2009-03-08 00:30:00 LISBON
T2 => 2009-03-08 07:30:00 EST = 2009-03-08 12:30:00 LISBON

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

AWK

<lang AWK>

  1. syntax: GAWK -f DATE_MANIPULATION.AWK

BEGIN {

   fmt = "%a %Y-%m-%d %H:%M:%S %Z" # DAY YYYY-MM-DD HH:MM:SS TZ
   split("March 7 2009 7:30pm EST",arr," ")
   M = (index("JanFebMarAprMayJunJulAugSepOctNovDec",substr(arr[1],1,3)) + 2) / 3
   D = arr[2]
   Y = arr[3]
   hhmm = arr[4]
   hh = substr(hhmm,1,index(hhmm,":")-1) + 0
   mm = substr(hhmm,index(hhmm,":")+1,2) + 0
   if (hh == 12 && hhmm ~ /am/) { hh = 0 }
   else if (hh < 12 && hhmm ~ /pm/) { hh += 12 }
   time = mktime(sprintf("%d %d %d %d %d %d",Y,M,D,hh,mm,0))
   printf("time:    %s\n",strftime(fmt,time))
   time += 12*60*60
   printf("+12 hrs: %s\n",strftime(fmt,time))
   exit(0)

} </lang>

output:

time:    Sat 2009-03-07 19:30:00 Eastern Standard Time
+12 hrs: Sun 2009-03-08 08:30:00 Eastern Daylight Time

BBC BASIC

<lang bbcbasic> INSTALL @lib$+"DATELIB"

     date$ = "March 7 2009 7:30pm EST"
     
     mjd% = FN_readdate(date$, "mdy", 0)
     colon% = INSTR(date$, ":")
     hours% = VAL(MID$(date$, colon%-2))
     IF INSTR(date$, "am") IF hours%=12  hours% -= 12
     IF INSTR(date$, "pm") IF hours%<>12 hours% += 12
     mins% = VAL(MID$(date$, colon%+1))
     
     now% = mjd% * 1440 + hours% * 60 + mins%
     new% = now% + 12 * 60 : REM 12 hours later
     
     PRINT FNformat(new%, "EST")
     PRINT FNformat(new% + 5 * 60, "GMT")
     PRINT FNformat(new% - 3 * 60, "PST")
     END
     
     DEF FNformat(datetime%, zone$)
     LOCAL mjd%, hours%, mins%, ampm$
     mjd% = datetime% DIV 1440
     hours% = (datetime% DIV 60) MOD 24
     mins% = datetime% MOD 60
     
     IF hours% < 12 THEN ampm$ = "am" ELSE ampm$ = "pm"
     IF hours% = 0 hours% += 12
     IF hours% > 12 hours% -= 12
     
     = FN_date$(mjd%, "MMMM d yyyy") + " " + STR$(hours%) + \
     \ ":" + RIGHT$("0"+STR$(mins%), 2) + ampm$ + " " + zone$
     ENDPROC

</lang> Output:

March 8 2009 7:30am EST
March 8 2009 12:30pm GMT
March 8 2009 4:30am PST

C

Works with: POSIX

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. 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++

Library: Boost

compiled with g++ -lboost_date_time <lang cpp>#include <string>

  1. include <iostream>
  2. include <boost/date_time/local_time/local_time.hpp>
  3. include <sstream>
  4. include <boost/date_time/gregorian/gregorian.hpp>
  5. include <vector>
  6. include <boost/algorithm/string.hpp>
  7. include <cstdlib>
  8. 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>

Delphi

<lang Delphi> program DateManipulation;

{$APPTYPE CONSOLE}

uses

 SysUtils,
 DateUtils;

function MonthNumber(aMonth: string): Word; begin

 //Convert a string value representing the month
 //to its corresponding numerical value
 if aMonth = 'January' then Result:= 1
 else if aMonth = 'February' then Result:= 2
 else if aMonth = 'March' then Result:= 3
 else if aMonth = 'April' then Result:= 4
 else if aMonth = 'May' then Result:= 5
 else if aMonth = 'June' then Result:= 6
 else if aMonth = 'July' then Result:= 7
 else if aMonth = 'August' then Result:= 8
 else if aMonth = 'September' then Result:= 9
 else if aMonth = 'October' then Result:= 10
 else if aMonth = 'November' then Result:= 11
 else if aMonth = 'December' then Result:= 12
 else Result:= 12;

end;

function ParseString(aDateTime: string): TDateTime; var

 strDay,
 strMonth,
 strYear,
 strTime: string;
 iDay,
 iMonth,
 iYear: Word;
 TimePortion: TDateTime;

begin

 //Decode the month from the given string
 strMonth:= Copy(aDateTime, 1, Pos(' ', aDateTime) - 1);
 Delete(aDateTime, 1, Pos(' ', aDateTime));
 iMonth:= MonthNumber(strMonth);
 //Decode the day from the given string
 strDay:= Copy(aDateTime, 1, Pos(' ', aDateTime) - 1);
 Delete(aDateTime, 1, Pos(' ', aDateTime));
 iDay:= StrToIntDef(strDay, 30);
 //Decode the year from the given string
 strYear:= Copy(aDateTime, 1, Pos(' ', aDateTime) -1);
 Delete(aDateTime, 1, Pos(' ', aDateTime));
 iYear:= StrToIntDef(strYear, 1899);
 //Decode the time value from the given string
 strTime:= Copy(aDateTime, 1, Pos(' ', aDateTime) -1);
 //Encode the date value and assign it to result
 Result:= EncodeDate(iYear, iMonth, iDay);
 //Encode the time value and add it to result
 if TryStrToTime(strTime, TimePortion) then
   Result:= Result + TimePortion;

end;

function Add12Hours(aDateTime: string): string; var

 tmpDateTime: TDateTime;

begin

 //Adding 12 hours to the given
 //date time string value
 tmpDateTime:= ParseString(aDateTime);
 tmpDateTime:= IncHour(tmpDateTime, 12);
 //Formatting the output
 Result:= FormatDateTime('mm/dd/yyyy hh:mm AM/PM', tmpDateTime);

end;

begin

 Writeln(Add12Hours('March 7 2009 7:30pm EST'));
 Readln;

end. </lang>

The output of the Delphi program is: "03/08/2009 07:30 AM"


Erlang

It is human readable to me. <lang Erlang> -module( date_manipulation ).

-export( [task/0] ).

task() -> {Date_time, TZ} = date_time_tz_from_string( "March 7 2009 7:30pm EST" ), Seconds1 = calendar:datetime_to_gregorian_seconds( Date_time ), Seconds2 = calendar:datetime_to_gregorian_seconds( {calendar:gregorian_days_to_date(0), {12, 0, 0}} ), Date_time_later = calendar:gregorian_seconds_to_datetime( Seconds1 + Seconds2 ), {Date_time_later, TZ}.


date_time_tz_from_string( String ) -> [Month, Date, Year, Time, TZ] = string:tokens( String, " " ), [Hour, Minute] = string:tokens( Time, ":" ), {{date_from_strings(Year, Month, Date), time_from_strings(Hour, Minute)}, TZ}.

date_from_strings( Year, Month, Date ) -> {erlang:list_to_integer(Year), date_from_strings_month(Month), erlang:list_to_integer(Date)}.

date_from_strings_month( "January" ) -> 1; date_from_strings_month( "February" ) -> 2; date_from_strings_month( "March" ) -> 3; date_from_strings_month( "April" ) -> 4; date_from_strings_month( "May" ) -> 5; date_from_strings_month( "June" ) -> 6; date_from_strings_month( "July" ) -> 7; date_from_strings_month( "August" ) -> 8; date_from_strings_month( "September" ) -> 9; date_from_strings_month( "October" ) -> 10; date_from_strings_month( "November" ) -> 11; date_from_strings_month( "December" ) -> 12.

time_from_strings( Hour, Minute_12hours ) -> {ok, [Minute], AM_PM} = io_lib:fread("~d", Minute_12hours ), {time_from_strings_hour( Hour, string:to_lower(AM_PM) ), Minute, 0}.

time_from_strings_hour( Hour, "am" ) -> erlang:list_to_integer( Hour ); time_from_strings_hour( Hour, "pm" ) -> erlang:list_to_integer( Hour ) + 12. </lang>

Output:
24> date_manipulation:task().
{{{2009,3,8},{7,30,0}},"EST"}

Euphoria

<lang Euphoria> --Date Manipulation task from Rosetta Code wiki --User:Lnettnay

include std/datetime.e

datetime dt

dt = new(2009, 3, 7, 19, 30) dt = add(dt, 12, HOURS) printf(1, "%s EST\n", {format(dt, "%B %d %Y %I:%M %p")}) </lang> Output

March 08 2009 07:30 AM EST

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>

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>

      1. MMM dd yyyy h:mma ###

d = parseDate["March 7 2009 7:30pm EST"] println[d + 12 hours -> Eastern] println[d + 12 hours -> Switzerland] // Extra credit </lang>

Output is:

AD 2009-03-08 AM 08:30:00.000 (Sun) Eastern Daylight Time
AD 2009-03-08 PM 01:30:00.000 (Sun) Central European Time

Go

<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() {

   if etz, err := time.LoadLocation("US/Eastern"); err == nil {
       time.Local = etz
   }
   fmt.Println("Input:             ", taskDate)
   t, err := time.Parse(taskFormat, taskDate)
   if err != nil {
       fmt.Println(err)
       return
   }
   t = t.Add(12 * time.Hour)
   fmt.Println("+12 hrs:           ", t)
   if _, offset := t.Zone(); offset == 0 {
       fmt.Println("No time zone info.")
       return
   }
   atz, err := time.LoadLocation("US/Arizona")
   if err == nil {
       fmt.Println("+12 hrs in Arizona:", t.In(atz))
   }

}</lang>

Output:
Input:              March 7 2009 7:30pm EST
+12 hrs:            2009-03-08 08:30:00 -0400 EDT
+12 hrs in Arizona: 2009-03-08 05:30:00 -0700 MST

Groovy

Solution:

Library: Joda Time version 2.1

<lang groovy>import org.joda.time.* import java.text.*

def dateString = 'March 7 2009 7:30pm EST'

def sdf = new SimpleDateFormat('MMMM d yyyy h:mma zzz')

DateTime dt = new DateTime(sdf.parse(dateString))

println (dt) println (dt.plusHours(12)) println (dt.plusHours(12).withZone(DateTimeZone.UTC))</lang>

Output:

2009-03-07T18:30:00.000-06:00
2009-03-08T07:30:00.000-05:00
2009-03-08T12:30:00.000Z

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


JavaScript

Input: March 7 2009 7:30pm EST

The input string is ambiguous since EST might represent any one of 3 different world time zones. Will assume US Eastern Standard Time of UTC -5 hours.

Javascript date objects are always in the local time zone. If a date and time is provided in a different time zone, it must be dealt with manually as the date object's time zone offset is read only. Consequently, there may be issues if daylight saving is observed in one location but not the other.

While ECMA-262 Ed 5 specifies a Date.parse method, it is not widely supported (2011) and parsing of strings other than the format specified are implementation dependent. Since the test string doesn't conform to the standard, it must be manually parsed.

<lang JavaScript>function add12hours(dateString) {

 // Get the parts of the date string
 var parts = dateString.split(/\s+/);
 var date  = parts[1];
 var month = parts[0];
 var year  = parts[2];
 var time  = parts[3];
 var ampm  = time && time.match(/[a-z]+$/i)[0];
 var hr    = Number(time.split(':')[0]);
 var min   = Number(time.split(':')[1].replace(/\D/g,));
 var zone  = parts[4].toUpperCase();
 var months = ['January','February','March','April','May','June',
    'July','August','September','October','November','December'];
 var zones = {'EST': 300, 'AEST': -600}; // Minutes to add to zone time to get UTC
 // Convert month name to number, zero indexed
 // Could use indexOf but not supported widely
 for (var i=0, iLen=months.length; i<iLen; i++) {
   if (months[i] == month) {
     month = i;
   }
 }
 if (typeof month != 'number') return; // Invalid month name provided
 // Convert hours to 24hr
 if (ampm && ampm.toLowerCase() == 'pm') {
   hr += 12;
 }
 // Add 12 hours to hours
 hr += 12;
 // Create a date object in local zone
 var d = new Date(year, month, date);
 d.setHours(hr, min, 0, 0);
 // Adjust minutes for the time zones
 d.setMinutes(d.getMinutes() + zones[zone] - d.getTimezoneOffset() );
 // d is now a local date representing the same moment as the
 // source date plus 12 hours
 return d;

}

var inputDateString = 'March 7 2009 7:30pm EST';

alert(

 'Input: ' + inputDateString + '\n' +
 '+12hrs in local time: ' + add12hours(inputDateString)
);</lang>

Lasso

<lang Lasso>local(date) = date('March 7 2009 7:30PM EST',-format='MMMM d yyyy h:mma z')

  1. date->add(-hour = 24)
  2. date->timezone = 'GMT'</lang>
Output:
March 9 2009 12:30AM GMT

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>

mIRC Scripting Language

<lang mirc>echo -ag $asctime($calc($ctime(March 7 2009 7:30pm EST)+43200))</lang>

NetRexx

<lang NetRexx>/* NetRexx */ options replace format comments java crossref symbols binary

import java.text.SimpleDateFormat import java.text.ParseException

runSample(arg) return

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ method manipulateDate(sampleDate, dateFmt, dHours = 0) private static

 formatter = SimpleDateFormat(dateFmt)
 msHours = dHours * 60 * 60 * 1000 -- hours in milliseconds
 day = formatter.parse(sampleDate)
 day.setTime(day.getTime() + msHours)
 formatted = formatter.format(day)
 return formatted

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ method runSample(arg) private static

 do
   sampleDate = 'March 7 2009 7:30pm EST'
   dateFmt = "MMMM d yyyy h:mma z"
   say sampleDate
   say manipulateDate(sampleDate, dateFmt, 12)
 catch ex = Exception
   ex.printStackTrace()
 end
 return

</lang> Output:

March 7 2009 7:30pm EST
March 8 2009 8:30AM EDT

ooRexx

version 1

<lang ooRexx>

 sampleDate = 'March 7 2009 7:30pm EST'
 Parse var sampleDate month day year time zone
 basedate = .DateTime~fromNormalDate(day month~left(3) year)
 basetime = .DateTime~fromCivilTime(time)
 -- this will give us this in a merged format...now we can add in the
 -- timezone informat
 mergedTime = (basedate + basetime~timeofday)~isoDate
 zone = .TimeZoneDataBase~getTimeZone(zone)
 finalTime = .DateTime~fromIsoDate(mergedTime, zone~datetimeOffset)
 say 'Original date:' finalTime~utcIsoDate
 say 'Result after adding 12 hours:' finalTime~addHours(12)~utcIsoDate
 say 'Result shifted to UTC:' finalTime~toTimeZone(0)~utcIsoDate
 say 'Result shifted to Pacific Standard Time:' finalTime~toTimeZone(.TimeZoneDataBase~getTimeZone('PST')~datetimeOffset)~utcIsoDate
 say 'Result shifted to NepalTime Time:' finalTime~toTimeZone(.TimeZoneDataBase~getTimeZone('NPT')~datetimeOffset)~utcIsoDate

-- a descriptor for timezone information

class timezone
method init
 expose code name offset altname region
 use strict arg code, name, offset, altname, region
 code~upper
attribute code GET
attribute name GET
attribute offset GET
attribute altname GET
attribute region GET
attribute datetimeOffset GET
 expose offset
 return offset * 60

-- our database of timezones

class timezonedatabase

-- initialize the class object. This occurs when the program is first loaded

method init class
 expose timezones
 timezones = .directory~new
 -- extract the timezone data which is conveniently stored in a method
 data = self~instanceMethod('TIMEZONEDATA')~source
 loop line over data
   -- skip over the comment delimiters, blank lines, and the 'return'
   -- lines that force the comments to be included in the source
   if line = '/*' | line = '*/' | line =  | line = 'return' then iterate
   parse var line '{' region '}'
   if region \=  then do
      zregion = region
      iterate
   end
   else do
      parse var line abbrev . '!' fullname '!' altname . '!' offset .
      timezone = .timezone~new(abbrev, fullname, offset, altname, zregion)
      timezones[timezone~code] = timezone
   end
 end
method getTimezone class
 expose timezones
 use strict arg code
 return timezones[code~upper]

-- this is a dummy method containing the timezone database data. -- we'll access the source directly and extract the data held in comments -- the two return statements force the comment lines to be included in the -- source rather than processed as part of comments between directives

method timeZoneData class private

return /* {Universal} UTC  ! Coordinated Universal Time  !  ! 0

{Europe} BST  ! British Summer Time  !  ! +1 CEST ! Central European Summer Time  !  ! +2 CET  ! Central European Time  !  ! +1 EEST ! Eastern European Summer Time  !  ! +3 EET  ! Eastern European Time  !  ! +2 GMT  ! Greenwich Mean Time  !  ! 0 IST  ! Irish Standard Time  !  ! +1 KUYT ! Kuybyshev Time  !  ! +4 MSD  ! Moscow Daylight Time  !  ! +4 MSK  ! Moscow Standard Time  !  ! +3 SAMT ! Samara Time  !  ! +4 WEST ! Western European Summer Time  !  ! +1 WET  ! Western European Time  !  ! 0

{North America} ADT  ! Atlantic Daylight Time  ! HAA  ! -3 AKDT ! Alaska Daylight Time  ! HAY  ! -8 AKST ! Alaska Standard Time  ! HNY  ! -9 AST  ! Atlantic Standard Time  ! HNA  ! -4 CDT  ! Central Daylight Time  ! HAC  ! -5 CST  ! Central Standard Time  ! HNC  ! -6 EDT  ! Eastern Daylight Time  ! HAE  ! -4 EGST ! Eastern Greenland Summer Time  !  ! 0 EGT  ! East Greenland Time  !  ! -1 EST  ! Eastern Standard Time  ! HNE,ET ! -5 HADT ! Hawaii-Aleutian Daylight Time  !  ! -9 HAST ! Hawaii-Aleutian Standard Time  !  ! -10 MDT  ! Mountain Daylight Time  ! HAR  ! -6 MST  ! Mountain Standard Time  ! HNR  ! -7 NDT  ! Newfoundland Daylight Time  ! HAT  ! -2.5 NST  ! Newfoundland Standard Time  ! HNT  ! -3.5 PDT  ! Pacific Daylight Time  ! HAP  ! -7 PMDT ! Pierre & Miquelon Daylight Time  !  ! -2 PMST ! Pierre & Miquelon Standard Time  !  ! -3 PST  ! Pacific Standard Time  ! HNP,PT ! -8 WGST ! Western Greenland Summer Time  !  ! -2 WGT  ! West Greenland Time  !  ! -3

{India and Indian Ocean} IST  ! India Standard Time  !  ! +5.5 PKT  ! Pakistan Standard Time  !  ! +5 BST  ! Bangladesh Standard Time  !  ! +6 -- Note: collision with British Summer Time NPT  ! Nepal Time  !  ! +5.75 BTT  ! Bhutan Time  !  ! +6 BIOT ! British Indian Ocean Territory Time ! IOT  ! +6 MVT  ! Maldives Time  !  ! +5 CCT  ! Cocos Islands Time  !  ! +6.5 TFT  ! French Southern and Antarctic Time  !  ! +5

  • /

return </lang>

version 2

This example is written using the Open Object Rexx dialect to take advantage of the DateTime built–in class. <lang REXX>/* Rexx */

 sampleDate = 'March 7 2009 7:30pm EST'
 Parse value sampleDate with tm td ty tt tz .
 Parse value time('l', tt, 'c') with hh ':' mm ':' ss '.' us .
 timezones. = 
 Call initTimezones
 mn = monthNameToNumber(tm)
 zuluOffset = getTZOffset(tz)
 Drop !TZ !MSG
 day.1.!TZ = zuluOffset
 day.1.!MSG = 'Original date:'
 day.1 = .DateTime~new(ty, mn, td, hh, mm, ss, us, day.1.!TZ * 60)
 day.2.!TZ = zuluOffset
 day.2.!MSG = 'Result after adding 12 hours to date:'
 day.2 = day.1~addHours(12)
 day.3.!TZ = getTZOffset('UTC') -- AKA GMT == Greenwich Mean Time
 day.3.!MSG = 'Result shifted to "UTC (Zulu)" time zone:'
 day.3 = day.1~toTimeZone(day.3.!TZ)
 day.4.!TZ = getTZOffset('PST') -- Pacific Standard Time
 day.4.!MSG = 'Result shifted to "Pacific Standard Time" time zone:'
 day.4 = day.2~toTimeZone(day.4.!TZ * 60)
 day.5.!TZ = getTZOffset('NPT') -- Nepal Time
 day.5.!MSG = 'Result shifted to "Nepal Time" time zone:'
 day.5 = day.2~toTimeZone(day.5.!TZ * 60)
 day.0 = 5
 Say 'Manipulate the date string "'sampleDate'" and present results in ISO 8601 timestamp format:'
 Say
 Loop d_ = 1 to day.0
   Say day.d_.!MSG
   Say day.d_~isoDate || getUTCOffset(day.d_.!TZ, 'z')
   Say
   End d_

Return 0

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ isTrue: Procedure; Return (1 == 1)

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ isFalse: Procedure; Return \isTrue()

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ monthNameToNumber: Procedure Do

 Parse arg tm .
 mnamesList = 'January February March April May June July August September October November December'
 Loop mn = 1 to mnamesList~words
   mnx = mnamesList~word(mn)
   If mnx~upper~abbrev(tm~upper, 3) then Do
     Leave mn
     End
   End mn
 Return mn

End Exit

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ getTZOffset: Procedure expose timezones. Do

 Parse upper arg tz .
 Drop !REGION !FULLNAME !OFFSET !ZNAMEALT
 offset = 0
 Loop z_ = 1 to timezones.0
   If tz = timezones.z_ then Do
     offset = timezones.z_.!OFFSET
     Leave z_
     End
   End z_
 
 Return offset;

End Exit

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ getUTCOffset: Procedure expose timezones. Do

 Parse arg oh ., zulu .
 oha = abs(oh)
 If oha = 0 & 'ZULU'~abbrev(zulu~upper, 1) then Do
   offset = 'Z'
   End
 else Do
   If oh < 0 then ew = '-'
             else ew = '+'
   om = oha * 60
   oom = om // 60 % 1
   ooh = om % 60
   offset = ew || ooh~right(2, 0) || oom~right(2, 0)
   End
 Return offset

End Exit

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ initTimezones: Procedure expose timezones. Do

 -- Read time zone info from formatted comment block below
 Drop !REGION !FULLNAME !OFFSET !ZNAMEALT
 timezones.0 = 0
 region    = 
 !datBegin = '__DATA__'
 !datEnd   = '__ENDD__'
 !reading  = isFalse()
 Loop l_ = 1 to sourceline()
   Parse value sourceline(l_) with sl 0 hd +8 .
   If !reading then Do
     If hd = !datEnd then Do
       !reading = isFalse()
       Leave l_
       End
     else Do
       Parse value sl with sl '--' .
       If sl~strip~length = 0 then Iterate l_
       Parse value sl with,
         0 '{' zRegion '}',
         0 zAbbrev . '!' zFullName '!' zAbbrevOther . '!' zUOffset .
         If zRegion~length \= 0 then Do
           region = zRegion
           Iterate l_
           End
         else Do
           z_ = timezones.0 + 1
           timezones.0 = z_
           timezones.z_ = zAbbrev~strip~upper
           timezones.z_.!FULLNAME = zFullName~strip
           timezones.z_.!OFFSET   = zUOffset~format
           timezones.z_.!ZNAMEALT = zAbbrevOther~strip~upper
           timezones.z_.!REGION   = region
           End
       End
     End
   else Do
     If hd = !datBegin then Do
       !reading = isTrue()
       End
     Iterate l_
     End    
   End l_
 Return timezones.0

End Exit /*

A "HERE" document, sort of...
Everything between the __DATA__ and __ENDD__ delimiters will be read into the timezones. stem:

__DATA__ {Universal} UTC  ! Coordinated Universal Time  !  ! 0

{Europe} BST  ! British Summer Time  !  ! +1 CEST ! Central European Summer Time  !  ! +2 CET  ! Central European Time  !  ! +1 EEST ! Eastern European Summer Time  !  ! +3 EET  ! Eastern European Time  !  ! +2 GMT  ! Greenwich Mean Time  !  ! 0 IST  ! Irish Standard Time  !  ! +1 KUYT ! Kuybyshev Time  !  ! +4 MSD  ! Moscow Daylight Time  !  ! +4 MSK  ! Moscow Standard Time  !  ! +3 SAMT ! Samara Time  !  ! +4 WEST ! Western European Summer Time  !  ! +1 WET  ! Western European Time  !  ! 0

{North America} ADT  ! Atlantic Daylight Time  ! HAA  ! -3 AKDT ! Alaska Daylight Time  ! HAY  ! -8 AKST ! Alaska Standard Time  ! HNY  ! -9 AST  ! Atlantic Standard Time  ! HNA  ! -4 CDT  ! Central Daylight Time  ! HAC  ! -5 CST  ! Central Standard Time  ! HNC  ! -6 EDT  ! Eastern Daylight Time  ! HAE  ! -4 EGST ! Eastern Greenland Summer Time  !  ! 0 EGT  ! East Greenland Time  !  ! -1 EST  ! Eastern Standard Time  ! HNE,ET ! -5 HADT ! Hawaii-Aleutian Daylight Time  !  ! -9 HAST ! Hawaii-Aleutian Standard Time  !  ! -10 MDT  ! Mountain Daylight Time  ! HAR  ! -6 MST  ! Mountain Standard Time  ! HNR  ! -7 NDT  ! Newfoundland Daylight Time  ! HAT  ! -2.5 NST  ! Newfoundland Standard Time  ! HNT  ! -3.5 PDT  ! Pacific Daylight Time  ! HAP  ! -7 PMDT ! Pierre & Miquelon Daylight Time  !  ! -2 PMST ! Pierre & Miquelon Standard Time  !  ! -3 PST  ! Pacific Standard Time  ! HNP,PT ! -8 WGST ! Western Greenland Summer Time  !  ! -2 WGT  ! West Greenland Time  !  ! -3

{India and Indian Ocean} IST  ! India Standard Time  !  ! +5.5 PKT  ! Pakistan Standard Time  !  ! +5 BST  ! Bangladesh Standard Time  !  ! +6 -- Note: collision with British Summer Time NPT  ! Nepal Time  !  ! +5.75 BTT  ! Bhutan Time  !  ! +6 BIOT ! British Indian Ocean Territory Time ! IOT  ! +6 MVT  ! Maldives Time  !  ! +5 CCT  ! Cocos Islands Time  !  ! +6.5 TFT  ! French Southern and Antarctic Time  !  ! +5

__ENDD__

  • /

</lang>

Output
Manipulate the date string "March 7 2009 7:30pm EST" and present results in ISO 8601 timestamp format:

Original date:
2009-03-07T19:30:00.000000-0500

Result after adding 12 hours to date:
2009-03-08T07:30:00.000000-0500

Result shifted to "UTC (Zulu)" time zone:
2009-03-08T00:30:00.000000Z

Result shifted to "Pacific Standard Time" time zone:
2009-03-08T04:30:00.000000-0800

Result shifted to "Nepal Time" time zone:
2009-03-08T18:15:00.000000+0545

Pascal

See Delphi

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

Perl 6

Perl 6 comes with a build-in DateTime type to support most aspects of standard civic time calculation that are not dependent on cultural idiosyncracies. Unfortunately, Perl 6 does not yet have a date parsing module (mostly due to a reticence to inflict Western cultural imperialism on other cultures...or maybe just due to laziness), but that just gives us another opportunity to demonstrate the built-in grammar support.

<lang perl6>my @month = <January February March April May June July August September October November December>; my %month = (@month Z=> ^12).flat, (@month».substr(0,3) Z=> ^12).flat, 'Sept' => 8;

grammar US-DateTime {

   rule TOP { <month> <day>','? <year>','? 
   token month {

(\w+)'.'? { make %month{$0} // die "Bad month name: $0" }

   }
   token day { (\d ** 1..2) { make +$0 } }
   token year { (\d ** 1..4) { make +$0 } }
   token time {

(\d ** 1..2) ':' (\d ** 2) \h* ( :i <[ap]> \.? m | ) { my $h = $0 % 12; my $m = $1; $h += 12 if $2 and $2.substr(0,1).lc eq 'p'; make $h * 60 + $m; }

   }
   token tz {  # quick and dirty for this task
       [
       |        EDT  { make -4 }
       | [ EST| CDT] { make -5 }
       | [ CST| MDT] { make -6 }
       | [ MST| PDT] { make -7 }
       | [ PST|AKDT] { make -8 }
       | [AKST|HADT] { make -9 }
       |  HAST
       ]
   }

}

$/ = US-DateTime.parse('March 7 2009 7:30pm EST') or die "Can't parse date";

my $year = $<year>.ast; my $month = $<month>.ast; my $day = $<day>.ast; my $hour = $

my $dt = DateTime.new(:$year, :$month, :$day, :$hour, :$minute, :$timezone).in-timezone(0);

$dt .= delta(12,hour);

say "12 hours later, GMT: $dt"; say "12 hours later, PST: $dt.in-timezone(-8 * 3600)";</lang>

Output:
12 hours later, GMT: 2009-02-08T12:30:00Z
12 hours later, PST: 2009-02-08T04:30:00-0800

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>

Pike

<lang Pike>> (Calendar.dwim_time("March 7 2009 7:30pm EST")+Calendar.Hour()*12)->set_timezone("CET")->format_ext_time(); Result: "Saturday, 7 March 2009 12:30:00"</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(seconds));</lang>

PowerShell

The .NET framework does not support parsing of time zone identifiers like "EST". We have to use time zone offsets like "-5". <lang PowerShell>$date = [DateTime]::Parse("March 7 2009 7:30pm -5" ) write-host $date write-host $date.AddHours(12) write-host [TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($date.AddHours(12),"Vladivostok Standard Time")</lang> Output (depends on user regional settings):

domingo, 08 de marzo de 2009 1:30:00
domingo, 08 de marzo de 2009 13:30:00
domingo, 08 de marzo de 2009 23:30:00

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>

Racket

The solution below ignores the time zone. <lang racket>

  1. lang racket

(require srfi/19)

(define 12hours (make-time time-duration 0 (* 12 60 60)))

(define (string->time s)

 (define t (date->time-utc (string->date s "~B~e~Y~H~M")))
 (if (regexp-match "pm" s)
     (add-duration t 12hours)
     t))

(date->string

(time-utc->date
 (add-duration
  (string->time "March 7 2009 7:30pm est" )
  12hours))
"~a ~d ~b ~Y ~H:~M")

</lang> Output: <lang racket> "Sun 08 Mar 2009 07:30" </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

REXX

This version only works with REXXes that support the DATE and TIME extended functions. <lang REXX>/*REXX pgm to add 12 hours to a date & time, showing the before & after.*/

aDate = 'March 7 2009 7:30pm EST'

parse var aDate mon dd yyyy hhmm tz . /*obtain the various parts&pieces*/

 mins = time('M',hhmm,'C')            /*get the # minutes past midnight*/
 mins = mins + (12*60)                /*add twelve hours to timestamp. */
nMins = mins // 1440                  /*compute #min into same/next day*/
 days = mins %  1440                  /*compute number of days "added".*/

aBdays = date('B',dd left(mon,3) yyyy) /*# of base days since REXX epoch*/ nBdays = aBdays + days /*now, add the # of days "added".*/

nDate = date(,nBdays,'B')             /*calculate the new date (maybe).*/
nTime = time('C',nMins,'M')           /*    "      "   "  time    "    */

say aDate ' + 12 hours ───► ' ndate ntime tz /*display new timestamp.*/

                                      /*stick a fork in it, we're done.*/</lang>

output

March 7 2009 7:30pm EST  +  12 hours  ───►  8 Mar 2009 7:30am EST

Ruby

The Time package in the standard library adds a parse method to the core Time class.

Library: RubyGems
Library: ActiveSupport

<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

  1. another timezone

require 'rubygems' require 'active_support' zone = ActiveSupport::TimeZone['Beijing'] remote = zone.at(new)

  1. 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>

Run BASIC

<lang runbasic>theDate$ = "March 7 2009 7:30pm EST"

monthName$ = "January February March April May June July August September October November December" for i = 1 to 12

 if word$(theDate$,1) = word$(monthName$,i) then monthNum = i			' turn month name to number

next i d = val(date$(monthNum;"/";word$(theDate$,2);"/";word$(theDate$,3))) ' days since Jan 1 1901 t$ = word$(theDate$,4) ' get time from theDate$ t1$ = word$(t$,1,"pm") ' strip pm t2$ = word$(t1$,1,":") + "." + word$(t1$,2,":") ' replace : with . t = val(t2$) if right$(t$,2) = "pm" then t = t + 12 ap$ = "pm" if t + 12 > 24 then

 d	= d + 1			' if over 24 hours add 1 to days since 1/1/1901
 ap$	= "am"

end if

print date$(d);" ";t1$;ap$</lang>

03/08/2009 7:30am

Scala

<lang scala>import java.text.SimpleDateFormat import java.util.{Calendar, Locale, TimeZone}

object DateManipulation {

 def main(args: Array[String]): Unit = {
   val input="March 7 2009 7:30pm EST"
   val df=new SimpleDateFormat("MMMM d yyyy h:mma z", Locale.ENGLISH)
   val c=Calendar.getInstance()
   c.setTime(df.parse(input))
   c.add(Calendar.HOUR_OF_DAY, 12)
   println(df.format(c.getTime))
   df.setTimeZone(TimeZone.getTimeZone("GMT"))
   println(df.format(c.getTime))
 }

}</lang>

Output:

March 8 2009 8:30AM EDT
March 8 2009 12:30PM GMT

Seed7

Time zone identifiers like "EST" are ambiguous. E.g.: "AST" is used to abbreviate both Atlantic Standard Time (UTC-04) and Arab Standard Time (UTC+03). Therefore parsing of such time zone identifiers is not supported by Seed7. ISO 8601 defines no time zone designators. Instead ISO 8601 specifies time offsets from UTC. In the example below EST is replaced with UTC-05.

<lang seed7>$ include "seed7_05.s7i";

 include "time.s7i";
 include "duration.s7i";

const func time: parseDate (in string: dateStri) is func

 result
   var time: result is time.value;
 local
   const array string: monthNames is [] ("January", "February", "March", "April",
       "May", "June", "July", "August", "September", "October", "November", "December");
   var array string: dateParts is 0 times "";
   var integer: month is 0;
   var string: timeStri is "";
 begin
   dateParts := split(dateStri, ' ');
   result.year := integer parse (dateParts[3]);
   result.month := 1;
   while monthNames[result.month] <> dateParts[1] do
     incr(result.month);
   end while;
   result.day := integer parse (dateParts[2]);
   timeStri := dateParts[4];
   if endsWith(timeStri, "am") then
     result.hour := integer parse (timeStri[.. pred(pos(timeStri, ':'))]);
   elsif endsWith(timeStri, "pm") then
     result.hour := integer parse (timeStri[.. pred(pos(timeStri, ':'))]) + 12;
   else
     raise RANGE_ERROR;
   end if;
   result.minute := integer parse (timeStri[succ(pos(timeStri, ':')) .. length(timeStri) - 2]);
   if dateParts[5] <> "UTC" then
     result.timeZone := 60 * integer parse (dateParts[5][4 ..]);
   end if;
 end func;

const proc: main is func

 local
   var time: aTime is time.value;
 begin
   aTime := parseDate("March 7 2009 7:30pm UTC-05");
   writeln("Given:         " <& aTime);
   aTime +:= 1 . DAYS;
   writeln("A day later:   " <& aTime);
   aTime := toUTC(aTime);
   writeln("In UTC:        " <& aTime);
 end func;</lang>

Output:

Given:         2009-03-07 19:30:00 UTC-5
A day later:   2009-03-08 19:30:00 UTC-5
In UTC:        2009-03-09 00:30:00 UTC

Smalltalk

Works with: GNU 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

Works with: Tcl version 8.5

<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>epoch=$(date -d 'March 7 2009 7:30pm EST +12 hours' +%s) date -d @$epoch TZ=Asia/Shanghai date -d @$epoch</lang>

output:

Sun Mar  8 08:30:00 EDT 2009
Sun Mar  8 20:30:00 CST 2009