Date manipulation: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|C}}: it it... it what?)
(smalltalk)
Line 50: Line 50:
or using <tt>System.out.println(date);</tt> as the last line:
or using <tt>System.out.println(date);</tt> as the last line:
<pre>Sun Mar 08 08:30:00 EDT 2009</pre>
<pre>Sun Mar 08 08:30:00 EDT 2009</pre>

=={{header|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 <code>readFromWithMeridian:andTimeZone:</code>.

The <code>aDict</code> 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):

<pre>March 8 2009 8:30AM EST
2009-03-08T13:30:00+00:00</pre>

=={{header|Tcl}}==
=={{header|Tcl}}==
{{works with|Tcl|8.5}}
{{works with|Tcl|8.5}}

Revision as of 16:52, 14 May 2009

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.

C

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <time.h>
  1. define BUF_LEN 100

int main() {

 struct tm ts;
 time_t t;
 const char *d = "March 7 2009 7:30pm EST";
 char buf[BUF_LEN];
 
 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)

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

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</lang>

Note the transition into daylight savings time in the interval (in the Eastern timezone).