class: Timestamp
authorStefan Vogel <sv@exept.de>
Tue, 11 Nov 2014 14:08:45 +0100
changeset 17031 d443175f7558
parent 17030 699aeda3a948
child 17032 e2c097d59814
class: Timestamp added: #utcOffsetWithoutDst changed: #asDate #asTime #utcOffset Fix for very large resp. very small dates in southern hemisphere
Timestamp.st
--- a/Timestamp.st	Tue Nov 11 14:04:17 2014 +0100
+++ b/Timestamp.st	Tue Nov 11 14:08:45 2014 +0100
@@ -1878,20 +1878,49 @@
         "/ fake an info which the OS cannot give me
         "/ we do not know about DST in the far future and in the long gone past.
         "/ Take the utcOffset without DST
-        ^ Epoch asLocalTimestamp utcOffset
+        ^ self utcOffsetWithoutDst.
     ].
 
     ^ (OperatingSystem computeTimeAndDateFrom:osTime) utcOffset
 
     "
      Timestamp now utcOffset
-     (Timestamp day:1 month:7 year:1995 hour:12 minutes:0 seconds:0) utcOffset
+     (Timestamp year:1995 month:7 day:1 hour:12 minute:0 second:0) utcOffset
+     (Timestamp year:1995 month:1 day:1 hour:12 minute:0 second:0) utcOffset
+     (Timestamp year:1689 month:7 day:1 hour:12 minute:0 second:0) utcOffset
+     (Timestamp year:4096 month:7 day:1 hour:12 minute:0 second:0) utcOffset
     "
 
     "Modified: 20.12.1995 / 17:28:49 / stefan"
     "Modified: 1.7.1996 / 15:21:29 / cg"
 !
 
+utcOffsetWithoutDst
+    "return the difference between UTC (Greenwich Mean Time) and the local time in seconds.
+     If daylight saving time applies to ourself, do not take that into account.
+
+     Add utcOffset to convert from local time to UTC time.
+     Subtract utcOffset to convert from UTC time to local time.
+
+     If utcOffset is negative, the local timezone is east of Greenwich.
+     If utcOffset is positive, the local timezone is west of Greenwich."
+
+    |offset epochInfo|
+
+    offset := 0.
+    [
+        "DST may be in winter in the southern hemisphere. If we are in DST, add some days"
+        epochInfo := OperatingSystem timeInfoFromSeconds:offset milliseconds:0 localTime:true.
+        offset := offset + (3600 * 24 * 90). "Add about 3 months"
+    ] doWhile:[epochInfo dst and:[offset < (3600 * 24 * 365) "avoid endless loop"]].
+
+    ^ epochInfo utcOffset
+
+    "
+     Timestamp now utcOffsetWithoutDst
+    "
+!
+
 weekInYear
     "return the week number of the receiver - 1 for Jan, 1st."
 
@@ -2072,13 +2101,12 @@
      otherwise if you convert an utcTimestamp, you'll get the utc date."
 
     (osTime between:MinOSTime and:MaxOSTime) ifFalse:[
-        |secondDelta dayDelta|
-
-        secondDelta := osTime // 1000.
+        |milliDelta dayDelta|
+
         "/ we do not know about DST in the far future and in the long gone past.
         "/ Take the utcOffset without DST
-        secondDelta := secondDelta - Epoch asLocalTimestamp utcOffset.
-        dayDelta := secondDelta // (24 * 3600).
+        milliDelta := osTime - (1000 * self utcOffsetWithoutDst).
+        dayDelta := milliDelta // (24 * 3600 * 1000).
         ^ Epoch asDate addDays:dayDelta.
     ].
     ^ self timeInfo asDate
@@ -2185,7 +2213,7 @@
         secondDelta := osTime // 1000.
         "/ we do not know about DST in the far future and in the long gone past.
         "/ Take the utcOffset without DST
-        secondDelta := (secondDelta - Epoch asLocalTimestamp utcOffset) rem:(24*3600).
+        secondDelta := (secondDelta - self utcOffsetWithoutDst) \\ (24*3600).
         ^ Epoch asTime addSeconds:secondDelta.
     ].
     ^ self timeInfo asTime
@@ -3860,11 +3888,11 @@
 !Timestamp class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/Timestamp.st,v 1.200 2014-11-11 12:12:44 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Timestamp.st,v 1.201 2014-11-11 13:08:45 stefan Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/Timestamp.st,v 1.200 2014-11-11 12:12:44 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Timestamp.st,v 1.201 2014-11-11 13:08:45 stefan Exp $'
 ! !