Merge jv
authorMerge Script
Sun, 07 Jun 2015 06:38:49 +0200
branchjv
changeset 18457 214d760f8247
parent 18442 bd42fa983e3f (current diff)
parent 18456 74744af7f90d (diff)
child 18461 bc3d3101c493
Merge
AbstractTime.st
Date.st
Time.st
Timestamp.st
UtcTimestamp.st
--- a/AbstractTime.st	Sat Jun 06 06:39:31 2015 +0200
+++ b/AbstractTime.st	Sun Jun 07 06:38:49 2015 +0200
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
  COPYRIGHT (c) 1995 by Claus Gittinger
               All Rights Reserved
@@ -287,6 +289,7 @@
     ^ '%h:%m:%s'
 ! !
 
+
 !AbstractTime class methodsFor:'private-instance creation'!
 
 fromOSTime:osTime
@@ -369,6 +372,24 @@
     "Modified: 1.7.1996 / 15:20:14 / cg"
 ! !
 
+!AbstractTime class methodsFor:'reading'!
+
+readFrom:aStringOrStream format:formatString
+    "see format description in readFrom:format:language:onError:"
+
+    ^ self 
+        readFrom:aStringOrStream format:formatString language:nil 
+        onError:[
+            self conversionErrorSignal raiseErrorString:'Timestamp format error'
+        ].
+!
+
+readFrom:aStringOrStream format:formatString onError:exceptionalValue
+    "see format description in readFrom:format:language:onError:"
+
+    ^ self readFrom:aStringOrStream format:formatString language:nil onError:exceptionalValue
+! !
+
 !AbstractTime class methodsFor:'timing evaluations'!
 
 microsecondsToRun:aBlock
@@ -1439,10 +1460,10 @@
 !AbstractTime class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/AbstractTime.st,v 1.91 2015-02-03 19:01:47 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/AbstractTime.st,v 1.92 2015-06-06 12:56:45 cg Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/AbstractTime.st,v 1.91 2015-02-03 19:01:47 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/AbstractTime.st,v 1.92 2015-06-06 12:56:45 cg Exp $'
 ! !
 
--- a/Date.st	Sat Jun 06 06:39:31 2015 +0200
+++ b/Date.st	Sun Jun 07 06:38:49 2015 +0200
@@ -298,7 +298,8 @@
     "return a new Date, given the day-number starting with 0 at 1.Jan 0;
      (i.e. 'Date fromDaysSince0:0' returns 1st Jan. 0).
      Date asDaysSince0 is the reverse operation.
-     Notice, that this is a private interface"
+     Notice, that this is a private interface.
+     Also notice: does not care for Gregorian/Julisn calendar change"
 
     |year rest d yearIncrement yearAsDaysFrom0|
 
@@ -446,16 +447,266 @@
     "
 !
 
+readFrom:aStringOrStream format:aSqueakFormatArrayOrFormatString
+    "return a new Date, reading a printed representation from aStream.
+     aSqueakFormatArrayOrFormatString may either be a squeak formatArray
+         1   day position (1, 2 or 3)
+         2   month position (1..3)
+         3   year position (1..3)
+     or a formatString (see printing instance protocol)."
+
+    ^ self 
+        readFrom:aStringOrStream
+        format:aSqueakFormatArrayOrFormatString 
+        onError:[ self conversionErrorSignal raise ]
+
+    "
+     Date readFrom:'19:11:1999' format:#( 1 2 3 )
+     Date readFrom:'19-nov-1999' format:#( 1 2 3 )
+     Date readFrom:'19:11:1999' format:#( 2 1 3 )  -> exception: wrong month
+     Date readFrom:'5:12:1999' format:#( 2 1 3 )  
+     Date readFrom:'may-12-1999' format:#( 2 1 3 )  
+     Date readFrom:'1999 may 12' format:#( 3 2 1 )  
+     Date readFrom:'12/31/2001' format:#( 2 1 3 ) 
+     Date readFrom:' 31.08.2001' format:#( 1 2 3 )    
+     Date readFrom:' 31.dec.2001' format:#( 1 2 3 )    
+     Date readFrom:' 31.Dec.2001' format:#( 1 2 3 )    
+     Date readFrom:' 31.dez.2001' format:#( 1 2 3 )    
+
+     Date readFrom:'31/12/01' format:'%d %m %y' onError:'fail'       
+     Date readFrom:'12/01' format:'%m %y' onError:'fail'       
+     Date readFrom:'01' format:'%y' onError:'fail'        
+     Date readFrom:'30.01' format:'%d %m' onError:'fail'       
+    "
+
+    "Created: 16.11.1995 / 22:50:17 / cg"
+    "Modified: 8.10.1996 / 19:25:39 / cg"
+!
+
+readFrom:aStringOrStream format:aFormatStringOrSqueakFormatArray language:languageOrNil onError:exceptionBlock
+    "return a new Date, reading a printed representation from aStream.
+     aFormatStringOrSqueakFormatArray may either be a squeak formatArray
+         1   day position (1, 2 or 3)
+         2   month position (1..3)
+         3   year position (1..3)
+     or a formatString (see printing instance protocol).
+     For now %d, %m, %monthName, %shortMonthName, %y, %Y, %y1900, %y2000, %y1950 and %y1980 are supported in the formatString.
+     y1900 converts 2-digit year YY into 19YY, 
+     y2000 into 20YY.
+     y1950, y1980 and Y are special; 
+     if the year is below 50/80/70, it is converted to 20YY, otherwise to 19YY. 
+     The formatString can have any of these characters '-.:,;/' as separator.
+     The format may be preceeded by a single numeric length (as in %2d) to specify how many
+     characters to read.
+     The formatString can also use a space as separator (for  ex. '%d %m %y') and any separator will be allowed.
+     However, when a character separator is defined, only that separator will be expected.
+     TODO: make this a general feature of all DateAndTime classes.
+    "
+
+    |str|
+
+    str := aStringOrStream readStream.
+
+    [
+        |day month year dayOfYear monthAndDay|
+
+        aFormatStringOrSqueakFormatArray isArray ifTrue:[
+            |arg|
+
+            arg := Array new:3.
+
+            1 to:3 do:[:i||v|
+                [str peek isLetterOrDigit] whileFalse:[str next].
+
+                v := (str peek isDigit) ifTrue:[Integer readFrom:str]
+                                       ifFalse:[str nextAlphaNumericWord].
+                arg at:i put:v
+            ].
+            year := arg at:(aFormatStringOrSqueakFormatArray at:3).
+            day := arg at:(aFormatStringOrSqueakFormatArray at:1).
+            month := arg at:(aFormatStringOrSqueakFormatArray at:2).
+        ] ifFalse:[
+            |formatStream fc c sel somePartAssoc len lStr|
+
+            formatStream := aFormatStringOrSqueakFormatArray readStream.
+            
+            [formatStream atEnd] whileFalse:[
+                fc := formatStream next.
+                fc == $% ifTrue:[
+                    sel := ''.
+                    len := nil.
+                    (fc := formatStream peekOrNil) notNil ifTrue:[
+                        fc isDigit ifTrue:[
+                            len := fc digitValue.
+                            formatStream next.
+                        ]
+                    ].    
+
+                    (fc := formatStream peekOrNil) notNil ifTrue:[
+                        fc == $( ifTrue:[
+                            formatStream next.
+                            sel := formatStream upTo:$)
+                        ] ifFalse:[
+                            sel := sel , (formatStream throughAnyForWhich:[:ch | ch isLetter])
+                        ]
+                    ].
+                    len notNil ifTrue:[
+                        lStr := str next:len.
+                        somePartAssoc := self readDatePartFrom:lStr readStream format:sel language:languageOrNil.
+                    ] ifFalse:[    
+                        somePartAssoc := self readDatePartFrom:str format:sel language:languageOrNil.
+                    ].
+                    somePartAssoc key == #day ifTrue:[
+                        day := somePartAssoc value.
+                    ] ifFalse:[somePartAssoc key == #month ifTrue:[
+                        month := somePartAssoc value.
+                    ] ifFalse:[somePartAssoc key == #year ifTrue:[
+                        year := somePartAssoc value.
+                    ] ifFalse:[somePartAssoc key == #dayOfYear ifTrue:[
+                        dayOfYear := somePartAssoc value.
+                    ] ifFalse:[
+                        self error:'unexpected date part'
+                    ]]]].
+                ] ifFalse:[
+                    fc == Character space ifTrue:[
+                        "/ Skip most possible separator characters 
+                        "/ (if not enough, should check for isNationalAlphaNumeric instead)
+                        [(c := str peek) isSeparator 
+                         or:[ '-.:,;/\|?<>[]{}()#@!!$&^+=~*_"`' includes:c]] whileTrue:[str next].    
+                    ] ifFalse:[
+                        str skipSeparators.
+                        str next ~= fc ifTrue:[^ exceptionBlock value].
+                        str skipSeparators.
+                    ]
+                ]
+            ].
+        ].
+
+        dayOfYear notNil ifTrue:[
+            monthAndDay := Date monthAndDayFromDayInYear:dayOfYear forYear:year.
+            month := (monthAndDay at:1).
+            day := (monthAndDay at:2).  
+        ].
+        
+        day isNil ifTrue:[ day := 1 ].
+        month isNil ifTrue:[ month := 1 ].
+        year isNil ifTrue:[ year := Date today year ].
+
+        (year between:0 and:99) ifTrue:[
+            year := UserPreferences current twoDigitDateHandler value:year.
+        ].
+        ^ self newDay:day month:month year:year.
+    ] on:Error do:[:ex| ^ exceptionBlock value].
+
+    "
+     Date readFrom:'31 December 1992' printFormat:#(1 2 3) onError:'fail' 
+     Date readFrom:'19:11:1999' printFormat:#(1 2 3) onError:'fail'  
+     Date readFrom:'December, 5 1992' printFormat:#(1 2 3) onError:'fail' 
+     Date readFrom:'3-jan-95' printFormat:#(1 2 3) onError:'fail'          
+     Date readFrom:'12/31/1992' printFormat:#(1 2 3) onError:'fail'       
+     Date readFrom:'15.4.1992' printFormat:#(1 2 3) onError:'wrong date'  -> german
+     Date readFrom:'10.4.1992' printFormat:#(1 2 3) onError:'fail'        -> german
+     Date readFrom:'10.4.1992' printFormat:#(1 2 3) onError:['wrong date']
+     Date readFrom:'32.4.1992' printFormat:#(1 2 3) onError:['wrong date']
+     Date readFrom:'fooBar' printFormat:#(1 2 3) onError:['wrong date']
+     Date readFrom:'10.4' printFormat:#(1 2 3) onError:['wrong date']
+     Date readFrom:'10041999' printFormat:#(1 2 3) onError:['wrong date']  
+
+     Date readFrom:'31/12/92' printFormat:#(1 2 3) onError:'fail'       
+     Date readFrom:'31/12/01' printFormat:#(1 2 3) onError:'fail'       
+
+     Date readFrom:'31/12/01' printFormat:'%d %m %y' onError:'fail'       
+     Date readFrom:'12/01' printFormat:'%m %y' onError:'fail'       
+     Date readFrom:'01' printFormat:'%y' onError:'fail'       
+     Date readFrom:'30.01' printFormat:'%d %m' onError:'fail'     
+     Date readFrom:'300180' printFormat:'%2d%2m%2y' onError:'fail' 
+     
+     Date readFrom:'300170' printFormat:'%2d%2m%2y' onError:'fail'      - gives 2070 as year
+     Date readFrom:'300170' printFormat:'%2d%2m%2Y' onError:'fail'      - gives 1970 as year
+     Date readFrom:'300169' printFormat:'%2d%2m%2y' onError:'fail'      - gives 2069 as year
+     Date readFrom:'300169' printFormat:'%2d%2m%2Y' onError:'fail'      - gives 2069 as year
+
+     Date readFrom:'300170' printFormat:'%2d%2m%2(y1950)' onError:'fail'  - gives 1970 as year   
+     Date readFrom:'300170' printFormat:'%2d%2m%2(y1980)' onError:'fail'  - gives 2070 as year   
+     Date readFrom:'300181' printFormat:'%2d%2m%2(y1980)' onError:'fail'  - gives 1981 as year   
+
+     Date readFrom:'2015103' printFormat:'%4y%3(dayOfYear)' onError:'fail'   
+
+     Date readFrom:'3-3-1995' printFormat:'%d %m %y' language: #de onError:'fail'          
+     Date readFrom:'3-März-1995' printFormat:'%d %monthName %y' language: #de onError:'fail'          
+     Date readFrom:'3-mär-1995' printFormat:'%d %shortMonthName %y' language: #de onError:'fail'   
+     Date readFrom:'3/mär/1995' printFormat:'%d %shortMonthName %y' language: #de onError:'fail'  
+     Date readFrom:'3/mär/1995' printFormat:'%d-%shortMonthName-%y' language: #de onError:'fail'          
+     Date readFrom:'3-dez-1995' printFormat:'%d %shortMonthName %y' language: #de onError:'fail'          
+     Date readFrom:'3-Dez-1995' printFormat:'%d %shortMonthName %y' language: #de onError:'fail'          
+     Date readFrom:'3-Dezember-1995' printFormat:'%d %monthName %y' language: #de onError:'fail'          
+
+    "
+
+    "Created: 16.11.1995 / 22:50:17 / cg"
+    "Modified: 8.10.1996 / 19:25:39 / cg"
+!
+
+readFrom:aStringOrStream format:aSqueakFormatArrayOrFormatString onError:exceptionBlock
+    "return a new Date, reading a printed representation from aStream.
+     aSqueakFormatArrayOrFormatString may either be a squeak formatArray
+         1   day position (1, 2 or 3)
+         2   month position (1..3)
+         3   year position (1..3)
+     or a formatString (see printing instance protocol).
+     All of the %-formats as in the printString are supported here.
+     (i.e. %d, %m and %y, %shortMonthName and %monthName)
+     In addition, %Y, %y1900, %y2000, %y1950 and %y1980 are supported:
+     y1900 converts 2-digit year YY into 19YY, y2000 into 20YY.
+     y1950, y1980 and Y are special; if the year is below 50/80/70, it is converted to 20YY, otherwise to 19YY. 
+     TODO: make this a general feature of all DateAndTime classes.
+    "
+
+    ^ self
+        readFrom:aStringOrStream 
+        format:aSqueakFormatArrayOrFormatString 
+        language:nil 
+        onError:exceptionBlock
+
+    "
+     Date readFrom:'31 December 1992' format:#(1 2 3) onError:'fail' 
+     Date readFrom:'19:11:1999' format:#(1 2 3) onError:'fail'  
+     Date readFrom:'December, 5 1992' format:#(1 2 3) onError:'fail' 
+     Date readFrom:'3-jan-95' format:#(1 2 3) onError:'fail'          
+     Date readFrom:'12/31/1992' format:#(1 2 3) onError:'fail'       
+     Date readFrom:'15.4.1992' format:#(1 2 3) onError:'wrong date'  -> german
+     Date readFrom:'10.4.1992' format:#(1 2 3) onError:'fail'        -> german
+     Date readFrom:'10.4.1992' format:#(1 2 3) onError:['wrong date']
+     Date readFrom:'32.4.1992' format:#(1 2 3) onError:['wrong date']
+     Date readFrom:'fooBar' format:#(1 2 3) onError:['wrong date']
+     Date readFrom:'10.4' format:#(1 2 3) onError:['wrong date']
+     Date readFrom:'10041999' format:#(1 2 3) onError:['wrong date']  
+
+     Date readFrom:'31/12/92' format:#(1 2 3) onError:'fail'       
+     Date readFrom:'31/12/01' format:#(1 2 3) onError:'fail'       
+
+     Date readFrom:'31/12/01' format:'%d %m %y' onError:'fail'       
+     Date readFrom:'12/01' format:'%m %y' onError:'fail'       
+     Date readFrom:'01' format:'%y' onError:'fail'       
+     Date readFrom:'30.01' format:'%d %m' onError:'fail'       
+     Date readFrom:'311201' format:'%2d%2m%2y' onError:'fail'       
+    "
+
+    "Created: 16.11.1995 / 22:50:17 / cg"
+    "Modified: 8.10.1996 / 19:25:39 / cg"
+!
+
 readFrom:aStringOrStream onError:exceptionBlock
     "return a new Date, reading a printed representation from aStream.
      Notice, that this is not the storeString format and 
      is different from the format expected by readFrom:.
+     
      BUG:
-       This method handles american format (i.e. month/day/year),
-       common format with letter month in the middle (10 December 2007)
+       For Smalltalk compatibility, this method handles american format (i.e. month/day/year),
+       the common format with letter month in the middle (10 December 2007)
        and ISO format (yyyy-mm-dd) - as long as yyyy is > 12.
 
-       It does not handle the german/french and other dd-mm-yyyy.
+       It does NOT handle the german/french and other dd-mm-yyyy formats.
        use readFrom:printFormat:onError: for this."
 
     ^ [
@@ -519,212 +770,6 @@
     "Modified: 8.10.1996 / 19:25:39 / cg"
 !
 
-readFrom:aStringOrStream printFormat:aSqueakFormatArrayOrFormatString
-    "return a new Date, reading a printed representation from aStream.
-     aSqueakFormatArrayOrFormatString may either be a squeak formatArray
-         1   day position (1, 2 or 3)
-         2   month position (1..3)
-         3   year position (1..3)
-     or a formatString (see printing instance protocol)."
-
-    ^ self 
-        readFrom:aStringOrStream
-        printFormat:aSqueakFormatArrayOrFormatString 
-        onError:[ self conversionErrorSignal raise ]
-
-    "
-     Date readFrom:'19:11:1999' printFormat:#( 1 2 3 )
-     Date readFrom:'19-nov-1999' printFormat:#( 1 2 3 )
-     Date readFrom:'19:11:1999' printFormat:#( 2 1 3 )  -> exception: wrong month
-     Date readFrom:'5:12:1999' printFormat:#( 2 1 3 )  
-     Date readFrom:'may-12-1999' printFormat:#( 2 1 3 )  
-     Date readFrom:'1999 may 12' printFormat:#( 3 2 1 )  
-     Date readFrom:'12/31/2001' printFormat:#( 2 1 3 ) 
-     Date readFrom:' 31.08.2001' printFormat:#( 1 2 3 )    
-     Date readFrom:' 31.dec.2001' printFormat:#( 1 2 3 )    
-     Date readFrom:' 31.Dec.2001' printFormat:#( 1 2 3 )    
-     Date readFrom:' 31.dez.2001' printFormat:#( 1 2 3 )    
-
-     Date readFrom:'31/12/01' printFormat:'%d %m %y' onError:'fail'       
-     Date readFrom:'12/01' printFormat:'%m %y' onError:'fail'       
-     Date readFrom:'01' printFormat:'%y' onError:'fail'        
-     Date readFrom:'30.01' printFormat:'%d %m' onError:'fail'       
-    "
-
-    "Created: 16.11.1995 / 22:50:17 / cg"
-    "Modified: 8.10.1996 / 19:25:39 / cg"
-!
-
-readFrom:aStringOrStream printFormat:aFormatStringOrSqueakFormatArray language:languageOrNil onError:exceptionBlock
-    "return a new Date, reading a printed representation from aStream.
-     aFormatStringOrSqueakFormatArray may either be a squeak formatArray
-         1   day position (1, 2 or 3)
-         2   month position (1..3)
-         3   year position (1..3)
-     or a formatString (see printing instance protocol).
-     For now %d, %m, %monthName, %shortMonthName and %y are supported in the formatString.
-     The formatString can have any of these characters '-.:,;/' as separator. 
-     The formatString can also use a space as separator (for  ex. '%d %m %y') and any separator will be allowed.
-     However, when a character separator is defined, only that separator will be expected.
-     TODO: make this a general feature of all DateAndTime classes.
-    "
-
-    |str|
-
-    str := aStringOrStream readStream.
-
-    [
-        |day month year|
-
-        aFormatStringOrSqueakFormatArray isArray ifTrue:[
-            |arg|
-
-            arg := Array new:3.
-
-            1 to:3 do:[:i||v|
-                [str peek isLetterOrDigit] whileFalse:[str next].
-
-                v := (str peek isDigit) ifTrue:[Integer readFrom:str]
-                                       ifFalse:[str nextAlphaNumericWord].
-                arg at:i put:v
-            ].
-            year := arg at:(aFormatStringOrSqueakFormatArray at:3).
-            day := arg at:(aFormatStringOrSqueakFormatArray at:1).
-            month := arg at:(aFormatStringOrSqueakFormatArray at:2).
-        ] ifFalse:[
-            |formatStream fc c sel somePartAssoc|
-
-            formatStream := aFormatStringOrSqueakFormatArray readStream.
-            
-            [formatStream atEnd] whileFalse:[
-                fc := formatStream next.
-                fc == $% ifTrue:[
-                    sel := ''.
-                    (fc := formatStream peekOrNil) notNil ifTrue:[
-                        fc == $( ifTrue:[
-                            formatStream next.
-                            sel := formatStream upTo:$)
-                        ] ifFalse:[
-                            sel := sel , (formatStream throughAnyForWhich:[:ch | ch isLetter])
-                        ]
-                    ].
-                    somePartAssoc := self readDatePartFrom:str format:sel language:languageOrNil.
-                    somePartAssoc key == #day ifTrue:[
-                        day := somePartAssoc value.
-                    ] ifFalse:[somePartAssoc key == #month ifTrue:[
-                        month := somePartAssoc value.
-                    ] ifFalse:[somePartAssoc key == #year ifTrue:[
-                        year := somePartAssoc value.
-                    ] ifFalse:[
-                        self error:'unexpected date part'
-                    ]]].
-                ] ifFalse:[
-                    fc == Character space ifTrue:[
-                        "/ Skip most possible separator characters 
-                        "/ (if not enough, should check for isNationalAlphaNumeric instead)
-                        [(c := str peek) isSeparator 
-                         or:[ '-.:,;/\|?<>[]{}()#@!!$&^+=~*_"`' includes:c]] whileTrue:[str next].    
-                    ] ifFalse:[
-                        str skipSeparators.
-                        str next ~= fc ifTrue:[^ exceptionBlock value].
-                        str skipSeparators.
-                    ]
-                ]
-            ].
-        ].
-
-        day isNil ifTrue:[ day := 1 ].
-        month isNil ifTrue:[ month := 1 ].
-        year isNil ifTrue:[ year := Date today year ].
-
-        (year between:0 and:99) ifTrue:[
-            year := UserPreferences current twoDigitDateHandler value:year.
-        ].
-        ^ self newDay:day month:month year:year.
-    ] on:Error do:[:ex| ^ exceptionBlock value].
-
-    "
-     Date readFrom:'31 December 1992' printFormat:#(1 2 3) onError:'fail' 
-     Date readFrom:'19:11:1999' printFormat:#(1 2 3) onError:'fail'  
-     Date readFrom:'December, 5 1992' printFormat:#(1 2 3) onError:'fail' 
-     Date readFrom:'3-jan-95' printFormat:#(1 2 3) onError:'fail'          
-     Date readFrom:'12/31/1992' printFormat:#(1 2 3) onError:'fail'       
-     Date readFrom:'15.4.1992' printFormat:#(1 2 3) onError:'wrong date'  -> german
-     Date readFrom:'10.4.1992' printFormat:#(1 2 3) onError:'fail'        -> german
-     Date readFrom:'10.4.1992' printFormat:#(1 2 3) onError:['wrong date']
-     Date readFrom:'32.4.1992' printFormat:#(1 2 3) onError:['wrong date']
-     Date readFrom:'fooBar' printFormat:#(1 2 3) onError:['wrong date']
-     Date readFrom:'10.4' printFormat:#(1 2 3) onError:['wrong date']
-     Date readFrom:'10041999' printFormat:#(1 2 3) onError:['wrong date']  
-
-     Date readFrom:'31/12/92' printFormat:#(1 2 3) onError:'fail'       
-     Date readFrom:'31/12/01' printFormat:#(1 2 3) onError:'fail'       
-
-     Date readFrom:'31/12/01' printFormat:'%d %m %y' onError:'fail'       
-     Date readFrom:'12/01' printFormat:'%m %y' onError:'fail'       
-     Date readFrom:'01' printFormat:'%y' onError:'fail'       
-     Date readFrom:'30.01' printFormat:'%d %m' onError:'fail'     
-
-     Date readFrom:'3-3-1995' printFormat:'%d %m %y' language: #de onError:'fail'          
-     Date readFrom:'3-März-1995' printFormat:'%d %monthName %y' language: #de onError:'fail'          
-     Date readFrom:'3-mär-1995' printFormat:'%d %shortMonthName %y' language: #de onError:'fail'   
-     Date readFrom:'3/mär/1995' printFormat:'%d %shortMonthName %y' language: #de onError:'fail'  
-     Date readFrom:'3/mär/1995' printFormat:'%d-%shortMonthName-%y' language: #de onError:'fail'          
-     Date readFrom:'3-dez-1995' printFormat:'%d %shortMonthName %y' language: #de onError:'fail'          
-     Date readFrom:'3-Dez-1995' printFormat:'%d %shortMonthName %y' language: #de onError:'fail'          
-     Date readFrom:'3-Dezember-1995' printFormat:'%d %monthName %y' language: #de onError:'fail'          
-
-    "
-
-    "Created: 16.11.1995 / 22:50:17 / cg"
-    "Modified: 8.10.1996 / 19:25:39 / cg"
-!
-
-readFrom:aStringOrStream printFormat:aSqueakFormatArrayOrFormatString onError:exceptionBlock
-    "return a new Date, reading a printed representation from aStream.
-     aSqueakFormatArrayOrFormatString may either be a squeak formatArray
-         1   day position (1, 2 or 3)
-         2   month position (1..3)
-         3   year position (1..3)
-     or a formatString (see printing instance protocol).
-     All of the %-formats as in the printString are supported here.
-     (i.e. %d, %m and %y, %shortMonthName and %monthName)
-     TODO: make this a general feature of all DateAndTime classes.
-    "
-
-    ^ self
-        readFrom:aStringOrStream 
-        printFormat:aSqueakFormatArrayOrFormatString 
-        language:nil 
-        onError:exceptionBlock
-
-    "
-     Date readFrom:'31 December 1992' printFormat:#(1 2 3) onError:'fail' 
-     Date readFrom:'19:11:1999' printFormat:#(1 2 3) onError:'fail'  
-     Date readFrom:'December, 5 1992' printFormat:#(1 2 3) onError:'fail' 
-     Date readFrom:'3-jan-95' printFormat:#(1 2 3) onError:'fail'          
-     Date readFrom:'12/31/1992' printFormat:#(1 2 3) onError:'fail'       
-     Date readFrom:'15.4.1992' printFormat:#(1 2 3) onError:'wrong date'  -> german
-     Date readFrom:'10.4.1992' printFormat:#(1 2 3) onError:'fail'        -> german
-     Date readFrom:'10.4.1992' printFormat:#(1 2 3) onError:['wrong date']
-     Date readFrom:'32.4.1992' printFormat:#(1 2 3) onError:['wrong date']
-     Date readFrom:'fooBar' printFormat:#(1 2 3) onError:['wrong date']
-     Date readFrom:'10.4' printFormat:#(1 2 3) onError:['wrong date']
-     Date readFrom:'10041999' printFormat:#(1 2 3) onError:['wrong date']  
-
-     Date readFrom:'31/12/92' printFormat:#(1 2 3) onError:'fail'       
-     Date readFrom:'31/12/01' printFormat:#(1 2 3) onError:'fail'       
-
-     Date readFrom:'31/12/01' printFormat:'%d %m %y' onError:'fail'       
-     Date readFrom:'12/01' printFormat:'%m %y' onError:'fail'       
-     Date readFrom:'01' printFormat:'%y' onError:'fail'       
-     Date readFrom:'30.01' printFormat:'%d %m' onError:'fail'       
-    "
-
-    "Created: 16.11.1995 / 22:50:17 / cg"
-    "Modified: 8.10.1996 / 19:25:39 / cg"
-!
-
 today
     "return a date, representing today.
      See also: Time now / Timestamp now."
@@ -1698,6 +1743,151 @@
 
     self obsoleteMethodWarning:'use #leapYear: (2014-09)'.
     ^ self leapYear:yearInteger
+!
+
+readFrom:aStringOrStream printFormat:aSqueakFormatArrayOrFormatString
+    "OBSOLETE: kept for backward compatibility.
+     return a new Date, reading a printed representation from aStream.
+     aSqueakFormatArrayOrFormatString may either be a squeak formatArray
+         1   day position (1, 2 or 3)
+         2   month position (1..3)
+         3   year position (1..3)
+     or a formatString (see printing instance protocol)."
+
+    ^ self 
+        readFrom:aStringOrStream
+        format:aSqueakFormatArrayOrFormatString 
+
+    "
+     Date readFrom:'19:11:1999' printFormat:#( 1 2 3 )
+     Date readFrom:'19-nov-1999' printFormat:#( 1 2 3 )
+     Date readFrom:'19:11:1999' printFormat:#( 2 1 3 )  -> exception: wrong month
+     Date readFrom:'5:12:1999' printFormat:#( 2 1 3 )  
+     Date readFrom:'may-12-1999' printFormat:#( 2 1 3 )  
+     Date readFrom:'1999 may 12' printFormat:#( 3 2 1 )  
+     Date readFrom:'12/31/2001' printFormat:#( 2 1 3 ) 
+     Date readFrom:' 31.08.2001' printFormat:#( 1 2 3 )    
+     Date readFrom:' 31.dec.2001' printFormat:#( 1 2 3 )    
+     Date readFrom:' 31.Dec.2001' printFormat:#( 1 2 3 )    
+     Date readFrom:' 31.dez.2001' printFormat:#( 1 2 3 )    
+
+     Date readFrom:'31/12/01' printFormat:'%d %m %y' onError:'fail'       
+     Date readFrom:'12/01' printFormat:'%m %y' onError:'fail'       
+     Date readFrom:'01' printFormat:'%y' onError:'fail'        
+     Date readFrom:'30.01' printFormat:'%d %m' onError:'fail'       
+    "
+
+    "Created: 16.11.1995 / 22:50:17 / cg"
+    "Modified: 8.10.1996 / 19:25:39 / cg"
+!
+
+readFrom:aStringOrStream printFormat:aFormatStringOrSqueakFormatArray language:languageOrNil onError:exceptionBlock
+    "OBSOLETE: kept for backward compatibility
+     return a new Date, reading a printed representation from aStream.
+     aFormatStringOrSqueakFormatArray may either be a squeak formatArray
+         1   day position (1, 2 or 3)
+         2   month position (1..3)
+         3   year position (1..3)
+     or a formatString (see printing instance protocol).
+     For now %d, %m, %monthName, %shortMonthName, %y, %y1900, %y2000, %y1950 and %y1980 are supported in the formatString.
+     y1900 converts 2-digit year YY into 19YY, y2000 into 20YY.
+     y1950 and y1980 are special; if the year is below 50/80, it is converted to 20YY, otherwise to 19YY. 
+     The formatString can have any of these characters '-.:,;/' as separator.
+     The format may be preceeded by a single numeric length (as in %2d) to specify how many
+     characters to read.
+     The formatString can also use a space as separator (for  ex. '%d %m %y') and any separator will be allowed.
+     However, when a character separator is defined, only that separator will be expected.
+     TODO: make this a general feature of all DateAndTime classes.
+    "
+
+    ^ self readFrom:aStringOrStream format:aFormatStringOrSqueakFormatArray language:languageOrNil onError:exceptionBlock
+
+
+    "
+     Date readFrom:'31 December 1992' format:#(1 2 3) onError:'fail' 
+     Date readFrom:'19:11:1999' format:#(1 2 3) onError:'fail'  
+     Date readFrom:'December, 5 1992' format:#(1 2 3) onError:'fail' 
+     Date readFrom:'3-jan-95' format:#(1 2 3) onError:'fail'          
+     Date readFrom:'12/31/1992' format:#(1 2 3) onError:'fail'       
+     Date readFrom:'15.4.1992' format:#(1 2 3) onError:'wrong date'  -> german
+     Date readFrom:'10.4.1992' format:#(1 2 3) onError:'fail'        -> german
+     Date readFrom:'10.4.1992' format:#(1 2 3) onError:['wrong date']
+     Date readFrom:'32.4.1992' format:#(1 2 3) onError:['wrong date']
+     Date readFrom:'fooBar' format:#(1 2 3) onError:['wrong date']
+     Date readFrom:'10.4' format:#(1 2 3) onError:['wrong date']
+     Date readFrom:'10041999' format:#(1 2 3) onError:['wrong date']  
+
+     Date readFrom:'31/12/92' format:#(1 2 3) onError:'fail'       
+     Date readFrom:'31/12/01' format:#(1 2 3) onError:'fail'       
+
+     Date readFrom:'31/12/01' format:'%d %m %y' onError:'fail'       
+     Date readFrom:'12/01' format:'%m %y' onError:'fail'       
+     Date readFrom:'01' format:'%y' onError:'fail'       
+     Date readFrom:'30.01' format:'%d %m' onError:'fail'     
+     Date readFrom:'300180' format:'%2d%2m%2y' onError:'fail' 
+     
+     Date readFrom:'300170' format:'%2d%2m%2y' onError:'fail'      - gives 2070 as year
+     Date readFrom:'300170' format:'%2d%2m%2(y1950)' onError:'fail'  - gives 1970 as year   
+     Date readFrom:'300170' format:'%2d%2m%2(y1980)' onError:'fail'  - gives 2070 as year   
+     Date readFrom:'300181' format:'%2d%2m%2(y1980)' onError:'fail'  - gives 1981 as year   
+
+     Date readFrom:'3-3-1995' format:'%d %m %y' language: #de onError:'fail'          
+     Date readFrom:'3-März-1995' format:'%d %monthName %y' language: #de onError:'fail'          
+     Date readFrom:'3-mär-1995' format:'%d %shortMonthName %y' language: #de onError:'fail'   
+     Date readFrom:'3/mär/1995' format:'%d %shortMonthName %y' language: #de onError:'fail'  
+     Date readFrom:'3/mär/1995' format:'%d-%shortMonthName-%y' language: #de onError:'fail'          
+     Date readFrom:'3-dez-1995' format:'%d %shortMonthName %y' language: #de onError:'fail'          
+     Date readFrom:'3-Dez-1995' format:'%d %shortMonthName %y' language: #de onError:'fail'          
+     Date readFrom:'3-Dezember-1995' format:'%d %monthName %y' language: #de onError:'fail'          
+    "
+
+    "Created: 16.11.1995 / 22:50:17 / cg"
+    "Modified: 8.10.1996 / 19:25:39 / cg"
+!
+
+readFrom:aStringOrStream printFormat:aSqueakFormatArrayOrFormatString onError:exceptionBlock
+    "return a new Date, reading a printed representation from aStream.
+     aSqueakFormatArrayOrFormatString may either be a squeak formatArray
+         1   day position (1, 2 or 3)
+         2   month position (1..3)
+         3   year position (1..3)
+     or a formatString (see printing instance protocol).
+     All of the %-formats as in the printString are supported here.
+     (i.e. %d, %m and %y, %shortMonthName and %monthName)
+     In addition, %y1900, %y2000, %y1950 and %y1980 are supported:
+     y1900 converts 2-digit year YY into 19YY, y2000 into 20YY.
+     y1950 and y1980 are special; if the year is below 50/80, it is converted to 20YY, otherwise to 19YY. 
+     TODO: make this a general feature of all DateAndTime classes.
+    "
+
+    ^ self readFrom:aStringOrStream format:aSqueakFormatArrayOrFormatString onError:exceptionBlock
+
+    "
+     Date readFrom:'31 December 1992' format:#(1 2 3) onError:'fail' 
+     Date readFrom:'19:11:1999' format:#(1 2 3) onError:'fail'  
+     Date readFrom:'December, 5 1992' format:#(1 2 3) onError:'fail' 
+     Date readFrom:'3-jan-95' format:#(1 2 3) onError:'fail'          
+     Date readFrom:'12/31/1992' format:#(1 2 3) onError:'fail'       
+     Date readFrom:'15.4.1992' format:#(1 2 3) onError:'wrong date'  -> german
+     Date readFrom:'10.4.1992' format:#(1 2 3) onError:'fail'        -> german
+     Date readFrom:'10.4.1992' format:#(1 2 3) onError:['wrong date']
+     Date readFrom:'32.4.1992' format:#(1 2 3) onError:['wrong date']
+     Date readFrom:'fooBar' format:#(1 2 3) onError:['wrong date']
+     Date readFrom:'10.4' format:#(1 2 3) onError:['wrong date']
+     Date readFrom:'10041999' format:#(1 2 3) onError:['wrong date']  
+
+     Date readFrom:'31/12/92' format:#(1 2 3) onError:'fail'       
+     Date readFrom:'31/12/01' format:#(1 2 3) onError:'fail'       
+
+     Date readFrom:'31/12/01' format:'%d %m %y' onError:'fail'       
+     Date readFrom:'12/01' format:'%m %y' onError:'fail'       
+     Date readFrom:'01' format:'%y' onError:'fail'       
+     Date readFrom:'30.01' format:'%d %m' onError:'fail'       
+     Date readFrom:'311201' format:'%2d%2m%2y' onError:'fail'       
+    "
+
+    "Created: 16.11.1995 / 22:50:17 / cg"
+    "Modified: 8.10.1996 / 19:25:39 / cg"
 ! !
 
 !Date class methodsFor:'private'!
@@ -1805,7 +1995,7 @@
 readDatePartFrom:str format:fmt language:languageOrNil
     "read a single component (such as %shortName) from str"
 
-    |dayName monthName day month year format string |
+    |dayName monthName day month year format string dayOfYear|
 
     format := fmt.
     string := str throughAnyForWhich:[:ch | ch isNationalAlphaNumeric].
@@ -1815,12 +2005,12 @@
         dayName := string.
         ^ nil.
     ].
-    (format sameAs:'d') ifTrue:[
+    ((format sameAs:'d') or:[format sameAs:'day']) ifTrue:[
         day := Integer readFrom:string.
         ^ #day -> day
     ].
 
-    (format sameAs:'m') ifTrue:[
+    ((format sameAs:'m') or:[format sameAs:'month']) ifTrue:[
         month := Integer readFrom:string.      
         ^ #month -> month
     ].
@@ -1837,21 +2027,64 @@
         ^ #month -> month
     ].
 
-    format = 'y' ifTrue:[
+    format = 'y1900' ifTrue:[
+        year := Integer readFrom:string.
+        year < 100 ifTrue:[
+            ^ #year -> (year + 1900)
+        ].
+        ^ #year -> year
+    ].
+    
+    format = 'y1950' ifTrue:[
+        "shift YY into 1950..2049; for 2k support of old date strings" 
+        year := Integer readFrom:string.
+        year < 100 ifTrue:[
+            year < 50 ifTrue:[
+                ^ #year -> (year + 2000)
+            ].
+            ^ #year -> (year + 1900)
+        ].
+        ^ #year -> year
+    ].
+
+    format = 'y1980' ifTrue:[
+        "shift YY into 1980..2079; for 2k support of old date strings" 
+        year := Integer readFrom:string.
+        year < 100 ifTrue:[
+            year < 80 ifTrue:[
+                ^ #year -> (year + 2000)
+            ].
+            ^ #year -> (year + 1900)
+        ].
+        ^ #year -> year
+    ].
+
+    (format = 'Y') ifTrue:[
+        "shift YY into 1970..2069; for 2k support of old date strings" 
+        year := Integer readFrom:string.
+        year < 100 ifTrue:[
+            year < 70 ifTrue:[
+                ^ #year -> (year + 2000)
+            ].
+            ^ #year -> (year + 1900)
+        ].
+        ^ #year -> year
+    ].
+    
+    ((format = 'y') or:[format sameAs:'year']) ifTrue:[
         year := Integer readFrom:string.
         year < 100 ifTrue:[
             ^ #year -> (year + 2000)
         ].
         ^ #year -> year
     ].
-    format = 'Y' ifTrue:[
-        year := Integer readFrom:string.
-        year >= 100 ifTrue:[
-            ^ #year -> year
-        ].
-        ^ #year -> (year + 2000) 
+    
+    (format sameAs:'dayOfYear') ifTrue:[
+        dayOfYear := Integer readFrom:string.      
+        ^ #dayOfYear -> dayOfYear
     ].
-    self error:'unknown format specifier'
+
+    self error:'unknown format specifier: ',format
 ! !
 
 !Date class methodsFor:'private-instance creation'!
@@ -3103,12 +3336,15 @@
 !Date methodsFor:'printing & storing'!
 
 addPrintBindingsTo:aDictionary
+    "see comment in addPrintBindingsTo:language:"
+    
     self addPrintBindingsTo:aDictionary language:nil.
 !
 
 addPrintBindingsTo:aDictionary language:languageOrNil
     "private print support: add bindings for printing to aDictionary.
-     languageOrNil can only be #en or nil for the current language.
+     languageOrNil can only be #en or nil for the current language setting (Smalltalk language).
+     
      valid format items are:
         %d              - day, 01..31                    0-padded to length 2
         %m              - month, 01..12                  0-padded to length 2
@@ -3121,7 +3357,17 @@
         %W              - week in year - unpadded
         %Y              - year, last 2 digits only i.e. 99, 04 (danger: year 2k bug)                     
 
+        %Y1900          - year, last 2 digits of 19YY only i.e. 99, 04 (danger: year 2k bug)
+                          raises an error, if the year is not in 1900..1999    
+        %Y2000          - year, last 2 digits of 20YY only i.e. 01, 04 or 15
+                          raises an error, if the year is not in 2000..2099    
+        %Y1950          - year, last 2 digits of 19YY or 20YY only i.e. 01, 04 or 80
+                          raises an error, if the year is not in 1950..2049    
+        %Y1980          - year, last 2 digits of 19YY or 20YY only i.e. 01, 04 or 80
+                          raises an error, if the year is not in 1980..2079    
+
         %(weekDay)      - day in week (1->monday, 2->tuesday, ... ,7->sunday)
+        %(dayOfYear)    - day in year (1..365/366)
 
         %(dayName)      - full day name     
         %(DayName)      - full day name, first character uppercase      
@@ -3148,7 +3394,7 @@
 
     |day ds dsPadded0 dsPaddedB month ms msPadded0 msPaddedB 
      year weekInYear monthName shortMonthName 
-     dayInWeek dayOfWeek dayName shortDayName ws wsPadded0|
+     dayInWeek dayOfWeek dayName dayOfYear shortDayName ws wsPadded0|
 
     day := self day.
     ds := day printString.
@@ -3167,6 +3413,7 @@
 
     dayInWeek := self dayInWeek.   "/ 1 .. 7
     dayOfWeek := self dayOfWeek.   "/ 0 .. 6
+    dayOfYear := self dayOfYear.   "/ 0 .. 6
 
     monthName := self class nameOfMonth:(self month) language:languageOrNil.
     dayName := self class nameOfDay:dayInWeek language:languageOrNil.
@@ -3197,6 +3444,26 @@
     aDictionary at:$M put:ms.
     aDictionary at:$y put:year.
     aDictionary at:$Y put:((year \\ 100) printStringLeftPaddedTo:2 with:$0).
+    aDictionary at:#Y1950 put:[ 
+                                (year between:1950 and:2049) ifFalse:[ 
+                                    self error:'year cannot be represented'
+                                ].
+                                (year between:1950 and:1999) ifTrue:[
+                                    (year - 1900) printStringLeftPaddedTo:2 with:$0
+                                ] ifFalse:[    
+                                    (year - 2000) printStringLeftPaddedTo:2 with:$0
+                                ]
+                            ].        
+    aDictionary at:#Y1980 put:[ 
+                                (year between:1980 and:2079) ifFalse:[ 
+                                    self error:'year cannot be represented'
+                                ].
+                                (year between:1980 and:1999) ifTrue:[
+                                    (year - 1900) printStringLeftPaddedTo:2 with:$0
+                                ] ifFalse:[    
+                                    (year - 2000) printStringLeftPaddedTo:2 with:$0
+                                ]
+                            ].        
     aDictionary at:$w put:wsPadded0.
     aDictionary at:$W put:ws.
 
@@ -3213,6 +3480,7 @@
     aDictionary at:#weekDay put:dayInWeek.
     aDictionary at:#weekday put:dayInWeek.
     aDictionary at:#weekDayUS put:dayOfWeek.
+    aDictionary at:#dayOfYear put:dayOfYear.
 
     aDictionary at:#shortDayName put:(shortDayName := self class abbreviatedNameOfDay:(self dayInWeek) language:languageOrNil).
     aDictionary at:#shortdayname put:shortDayName asLowercase.
@@ -3266,6 +3534,8 @@
      Date today printOn:Transcript format:'%(DayName), %D%(nth) of %(MonthName), %y'   
      Date today printOn:Transcript format:'%(ShortDayName), %D-%(ShortMonthName)-%y'   
      Date today printOn:Transcript format:'%d%m%Y'                                      (millenium bug format - danger)
+     Date today printOn:Transcript format:'%d%m%(Y1950)'                                (millenium bug partial workaround format - danger)
+     Date today printOn:Transcript format:'%d%m%(Y1980)'                                (millenium bug partial workaround format - danger)
      Date today printOn:Transcript format:'Today is the %(weekDay) day of the week'     
      Date today printOn:Transcript format:'Today is %(year).%(monthRoman).%D'           (hungarian format)
      Date today printOn:Transcript format:'Today is %(D) %(monthRoman) %y'              (poland)
@@ -3273,12 +3543,15 @@
      Date today printOn:Transcript format:'Today is %(D)/%(mon)-%Y'                     (sweden)
      Date today printOn:Transcript format:'Anno domini %(yearRoman)'
      Date today printOn:Transcript format:'%y年%(mon)月%d日'                               (select a font, which can display those chars)
+     Date today printOn:Transcript format:'%(dayOfYear)'                                      
     "
+
     "short form (as in blogs like www.stackoverflow, www.superuser etc.)
      Date today printOn:Transcript format:'%(MonthName) %D ''%Y'     
      Timestamp now printOn:Transcript format:'%(MonthName) %D ''%Y at %h:%m'     
     "
-    "
+
+    "Squeak format spec:
      String streamContents:[:s |
         Date today printOn:s format:#(1 2 3 $/ 1 2)
      ]    
@@ -3475,11 +3748,11 @@
 !Date class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/Date.st,v 1.170 2015-05-17 20:49:07 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Date.st,v 1.174 2015-06-06 11:18:11 cg Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/Date.st,v 1.170 2015-05-17 20:49:07 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Date.st,v 1.174 2015-06-06 11:18:11 cg Exp $'
 ! !
 
 
--- a/TZTimestamp.st	Sat Jun 06 06:39:31 2015 +0200
+++ b/TZTimestamp.st	Sun Jun 07 06:38:49 2015 +0200
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
  COPYRIGHT (c) 2014 by eXept Software AG
               All Rights Reserved
@@ -123,8 +125,8 @@
     |ti|
 
     "/ utcOffset negative: east of GMT
-    ti := OperatingSystem computeUTCTimeAndDateFrom:(osTime - (utcOffset * 1000)).
-    ti utcOffset:utcOffset.
+    ti := OperatingSystem computeUTCTimeAndDateFrom:(osTime - ((utcOffset ? 0) * 1000)).
+    ti utcOffset:(utcOffset ? 0).
     ^ ti
 !
 
@@ -138,7 +140,7 @@
      If utcOffset is negative, the local timezone is east of Greenwich.
      If utcOffset is positive, the local timezone is west of Greenwich."
 
-    ^  utcOffset
+    ^ utcOffset ? 0
 !
 
 utcOffset:seconds
@@ -184,7 +186,7 @@
 
 speciesNew
     ^ self species basicNew 
-        utcOffset:utcOffset;
+        utcOffset:(utcOffset ? 0);
         yourself
 !
 
@@ -195,10 +197,10 @@
 !TZTimestamp class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/TZTimestamp.st,v 1.10 2015-02-06 10:36:58 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/TZTimestamp.st,v 1.12 2015-06-06 12:42:27 cg Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/TZTimestamp.st,v 1.10 2015-02-06 10:36:58 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/TZTimestamp.st,v 1.12 2015-06-06 12:42:27 cg Exp $'
 ! !
 
--- a/Time.st	Sat Jun 06 06:39:31 2015 +0200
+++ b/Time.st	Sun Jun 07 06:38:49 2015 +0200
@@ -1,5 +1,3 @@
-"{ Encoding: utf8 }"
-
 "
  COPYRIGHT (c) 1989 by Claus Gittinger
 	      All Rights Reserved
@@ -187,6 +185,133 @@
     "
 !
 
+readFrom:aStringOrStream format:formatString language:languageOrNil onError:exceptionalValue
+    "return a new Time, reading a printed representation from aStream using a formatString.
+     The formatString is similar to the one used when printing.
+     On error, exceptionalValue is returned.
+     If exceptionalValue is a one-arg block, an error message is passed as argument.
+     Format:
+        %h      hours, 00..23 (i.e. european)  0-padded to length 2
+        %u      hours, 00..12 (i.e. us)        0-padded to length 2
+        %m      minutes, 00..59                0-padded to length 2
+        %s      seconds, 00..59                0-padded to length 2
+        %i      milliseconds, 000..999         0-padded to length 3
+        %a      am/pm
+
+     an optional length after the % gives a field length;
+        i.e. %2h%2m%2s parses '123557' as 12:35:37
+
+     Please consider using a standard format, such as iso8601.
+    "
+
+    |hour minute second millisecond
+     utcOffset inStream formatStream error fChar format itemHandler
+     len s|
+
+    error := [:msg |
+                exceptionalValue isBlock ifTrue:[
+                    ^ exceptionalValue valueWithOptionalArgument:'format error'
+                ] ifFalse:[
+                    ^ exceptionalValue value
+                ].
+             ].
+
+    itemHandler := [:format |
+        |input|
+
+        input := len isNil ifTrue:[ inStream ] ifFalse:[ inStream next: len ].
+
+        ( format = 'h' or:[ format = 'H' ]) ifTrue:[
+            hour := Integer readFrom:input onError:[ error value:'invalid hour' ].
+
+        ] ifFalse:[ ( format = 'u'  or:[ format = 'U']) ifTrue:[
+            hour := Integer readFrom:input onError:[ error value:'invalid hour' ].
+
+        ] ifFalse:[ ( format = 'm'  or:[ format = 'M' ]) ifTrue:[
+            minute := Integer readFrom:input onError:[ error value:'invalid minute' ].
+
+        ] ifFalse:[ ( format = 's'  or:[ format = 'S' ]) ifTrue:[
+            second := Integer readFrom:input onError:[ error value:'invalid second' ].
+
+        ] ifFalse:[ ( format = 'i'  or:[ format = 'I' ]) ifTrue:[
+            millisecond := Integer readFrom:input onError:[ error value:'invalid millsecond' ].
+
+        ] ifFalse:[ ( format = 'tz' ) ifTrue:[
+            utcOffset := Timestamp utcOffsetFrom:input.
+            utcOffset isNil ifTrue:[ error value:'invalid timezone' ]
+        ] ifFalse:[ ( format = 'a' ) ifTrue:[
+            s := (input next:2) asLowercase.
+            s = 'am' ifTrue:[
+                (hour between:0 and:12) ifFalse:[ error value:'invalid hour' ]
+            ] ifFalse:[
+                s = 'pm' ifTrue:[
+                    (hour between:1 and:12) ifFalse:[ error value:'invalid hour' ].
+                    hour := hour + 12.
+                ] ifFalse:[
+                    error value:'invalid am/pm'
+                ]
+            ]
+
+        ] ifFalse:[
+            error value:'unhandled format:',format
+        ]]]]]]]
+    ].
+
+    hour := 0.
+    minute := 0.
+    second := 0.
+    millisecond := 0.
+    utcOffset := 0.
+
+    inStream := aStringOrStream readStream.
+    formatStream := formatString readStream.
+
+    [formatStream atEnd] whileFalse:[
+        fChar := formatStream next.
+        fChar = Character space ifTrue:[
+            inStream peek isSeparator ifFalse:[ error value: 'format error; space expcected' ].
+            inStream skipSeparators.
+        ] ifFalse:[
+            fChar == $% ifTrue:[
+                len := nil.
+                (formatStream peek isDigit) ifTrue:[
+                    len := Integer readFrom:formatStream onError:[ error value: 'format error; invalid length' ]
+                ].
+                (formatStream peek == $() ifTrue:[
+                    formatStream next.
+                    format := formatStream upTo:$).
+                ] ifFalse:[
+                    (formatStream peek == ${) ifTrue:[
+                        formatStream next.
+                        format := formatStream upTo:$}.
+                    ] ifFalse:[
+                        (formatStream peek isLetter) ifTrue:[
+                            format := formatStream nextAlphaNumericWord.
+                        ] ifFalse:[
+                            error value:'unhandled format:',formatStream peek
+                        ]
+                    ]
+                ].
+                itemHandler value:format.
+            ] ifFalse:[
+                inStream peek = fChar ifFalse:[^ error value: 'format error; ',fChar,' expcected'].
+                inStream next.
+            ]
+        ].
+    ].
+
+    ^ (self 
+        hours:(hour ? 0) minutes:(minute ? 0) seconds:(second ? 0) milliseconds:millisecond) 
+            + utcOffset
+
+    "
+     Time readFrom:'13:11:06' format:'%h:%m:%s' language:nil onError:[self halt]
+     Time readFrom:'131106' format:'%2h%2m%2s' language:nil onError:[self halt]
+     Time readFrom:'7:30pm EST' format:'%u:%m%a %tz' language:#en onError:[self halt]
+     Time readFrom:'7:30pm UTC' format:'%u:%m%a %tz' language:#en onError:[self halt]
+    "
+!
+
 readFrom:aStringOrStream onError:exceptionBlock
     "return a new Time, reading a printed representation from aStream.
      If no am/pm follows the time, the string is interpreted as
@@ -707,7 +832,6 @@
     "
 ! !
 
-
 !Time methodsFor:'printing & storing'!
 
 print12HourFormatOn:aStream
@@ -953,10 +1077,10 @@
 !Time class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/Time.st,v 1.103 2015-03-24 07:20:13 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Time.st,v 1.104 2015-06-06 12:57:19 cg Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/Time.st,v 1.103 2015-03-24 07:20:13 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Time.st,v 1.104 2015-06-06 12:57:19 cg Exp $'
 ! !
 
--- a/Timestamp.st	Sat Jun 06 06:39:31 2015 +0200
+++ b/Timestamp.st	Sun Jun 07 06:38:49 2015 +0200
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
  COPYRIGHT (c) 1989 by Claus Gittinger
 	      All Rights Reserved
@@ -781,6 +783,7 @@
         %d             - day
         %D             - day
         %(day)         - day
+        %(dayOfYear)   - 1..365/366
 
         %(month)       - month
 
@@ -792,6 +795,8 @@
                          72..99 map to 1972..1999;
         %Y1900          - year, last 2 digits only, map to 1900..1999
         %Y2000          - year, last 2 digits only, map to 2000..2099
+        %Y1950          - year, last 2 digits only, map to 1950..2049
+        %Y1980          - year, last 2 digits only, map to 1980..2079
 
      an optional length after the % gives a field length;
         i.e. %2h%2m%2s parses '123557' as 12:35:37
@@ -800,14 +805,14 @@
      Please consider using a standard format, such as iso8601.
     "
 
-    |day month year
+    |day month year dayOfYear monthAndDay
      hour minute second millisecond
      utcOffset inStream formatStream error fChar format itemHandler
      len now s|
 
     error := [:msg |
                 exceptionalValue isBlock ifTrue:[
-                    ^ exceptionalValue valueWithOptionalArgument:'format error; space expcected'
+                    ^ exceptionalValue valueWithOptionalArgument:'format error'
                 ] ifFalse:[
                     ^ exceptionalValue value
                 ].
@@ -815,6 +820,7 @@
 
     itemHandler := [:format |
         |input|
+        
         input := len isNil ifTrue:[ inStream ] ifFalse:[ inStream next: len ].
 
         ( #('d' 'D' 'day' ) includes:format ) ifTrue:[
@@ -829,22 +835,43 @@
         ] ifFalse:[ ( format = 'Y' ) ifTrue:[
             year := Integer readFrom:input onError:[ error value:'invalid year' ].
             (year between:0 and: 99) ifFalse:[ error value:'invalid year' ].
-            (year between:0 and:71) ifTrue:[
+            (year < 70) ifTrue:[
+                year := year + 2000
+            ] ifFalse:[
                 year := year + 1900
-            ] ifFalse:[
-                year := year + 2000
             ]
 
         ] ifFalse:[ (format = 'monthName') ifTrue:[
             s := input nextMatching:[:c | c isLetter] thenMatching:[:c | c isLetter].
             month := Date indexOfMonth:s asLowercase language:languageOrNil
 
-        ] ifFalse:[ ( format = 'Y1900' ) ifTrue:[
+        ] ifFalse:[ (format = 'dayOfYear') ifTrue:[
+            dayOfYear := Integer readFrom:input onError:[ error value:'invalid day of year' ].
+
+        ] ifFalse:[ ( format sameAs: 'Y1900' ) ifTrue:[
             year := Integer readFrom:input onError:[ error value:'invalid year' ].
             (year between:0 and: 99) ifFalse:[ error value:'invalid year' ].
             year := year + 1900
 
-        ] ifFalse:[ ( format = 'Y2000' ) ifTrue:[
+        ] ifFalse:[ ( format sameAs:  'Y1950' ) ifTrue:[
+            year := Integer readFrom:input onError:[ error value:'invalid year' ].
+            (year between:0 and: 99) ifFalse:[ error value:'invalid year' ].
+            (year between:0 and: 49) ifTrue:[ 
+                year := year + 2000
+            ] ifFalse:[    
+                year := year + 1900
+            ]  
+
+        ] ifFalse:[ ( format sameAs:  'Y1980' ) ifTrue:[
+            year := Integer readFrom:input onError:[ error value:'invalid year' ].
+            (year between:0 and: 99) ifFalse:[ error value:'invalid year' ].
+            (year between:0 and: 79) ifTrue:[ 
+                year := year + 2000
+            ] ifFalse:[    
+                year := year + 1900
+            ]  
+
+        ] ifFalse:[ ( format sameAs:  'Y2000' ) ifTrue:[
             year := Integer readFrom:input onError:[ error value:'invalid year' ].
             (year between:0 and: 99) ifFalse:[ error value:'invalid year' ].
             year := year + 2000
@@ -882,8 +909,8 @@
 
         ] ifFalse:[
             error value:'unhandled format:',format
-        ]]]]]]]]]]]]]]
-   ].
+        ]]]]]]]]]]]]]]]]]
+    ].
 
     hour := 0.
     minute := 0.
@@ -931,14 +958,29 @@
     year isNil ifTrue:[
         year := (now := Timestamp now) year
     ].
-
-    ^ (self year:year month:month day:day hour:(hour ? 0) minute:(minute ? 0) second:(second ? 0) millisecond:millisecond) + utcOffset
+    
+    dayOfYear notNil ifTrue:[
+        monthAndDay := Date monthAndDayFromDayInYear:dayOfYear forYear:year.
+        month := (monthAndDay at:1).
+        day := (monthAndDay at:2).  
+    ].
+    
+    ^ (self 
+        year:year month:month day:day 
+        hour:(hour ? 0) minute:(minute ? 0) second:(second ? 0) millisecond:millisecond) 
+            + utcOffset
 
     "
      Timestamp readFrom:'20-2-1995 13:11:06' format:'%day-%month-%year %h:%m:%s' language:nil onError:[self halt]
      Timestamp readFrom:'20021995131106' format:'%2d%2month%4y%2h%2m%2s' language:nil onError:[self halt]
+     Timestamp readFrom:'200295131106' format:'%2d%2month%2y%2h%2m%2s' language:nil onError:[self halt]
+     Timestamp readFrom:'200260131106' format:'%2d%2month%2(y1900)%2h%2m%2s' language:nil onError:[self halt]
+     Timestamp readFrom:'200260131106' format:'%2d%2month%2(y2000)%2h%2m%2s' language:nil onError:[self halt]
+     Timestamp readFrom:'200260131106' format:'%2d%2month%2(y1950)%2h%2m%2s' language:nil onError:[self halt]
+     Timestamp readFrom:'200260131106' format:'%2d%2month%2(y1980)%2h%2m%2s' language:nil onError:[self halt]
      Timestamp readFrom:'March 7 2009 7:30pm EST' format:'%monthName %day %year %u:%m%a %tz' language:#en onError:[self halt]
      Timestamp readFrom:'March 7 2009 7:30pm UTC' format:'%monthName %day %year %u:%m%a %tz' language:#en onError:[self halt]
+     Timestamp readFrom:'2015103' format:'%4y%3dayOfYear' onError:[self halt]
     "
 !
 
@@ -2384,11 +2426,19 @@
     super addPrintBindingsTo:dict language:languageOrNil.
 
     date year == Date today year ifTrue:[
-	dict at:#yearOrTime put:('%h:%m' expandPlaceholdersWith:dict).
+        dict at:#yearOrTime put:('%h:%m' expandPlaceholdersWith:dict).
     ].
 
     "
-	Timestamp now addPrintBindingsTo:Dictionary new inspect language:nil
+     |d|
+     d := Dictionary new.
+     Timestamp now addPrintBindingsTo:d language:nil.
+     d inspect.
+    "
+    
+    "used by:
+        Timestamp now printStringFormat:'%y-%m-%d'
+        Timestamp now printStringFormat:'%(dayOfYear)'
     "
 !
 
@@ -3908,11 +3958,11 @@
 !Timestamp class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/Timestamp.st,v 1.215 2015-06-05 17:41:37 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Timestamp.st,v 1.220 2015-06-06 12:57:00 cg Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/Timestamp.st,v 1.215 2015-06-05 17:41:37 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Timestamp.st,v 1.220 2015-06-06 12:57:00 cg Exp $'
 ! !
 
 
--- a/UtcTimestamp.st	Sat Jun 06 06:39:31 2015 +0200
+++ b/UtcTimestamp.st	Sun Jun 07 06:38:49 2015 +0200
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
  COPYRIGHT (c) 2011 by eXept Software AG
               All Rights Reserved
@@ -11,6 +13,8 @@
 "
 "{ Package: 'stx:libbasic' }"
 
+"{ NameSpace: Smalltalk }"
+
 Timestamp subclass:#UtcTimestamp
 	instanceVariableNames:''
 	classVariableNames:''
@@ -72,6 +76,8 @@
 !
 
 utcOffset
+    "I am an UTC timestamp, so there is no offset"
+    
     ^ 0
 !
 
@@ -142,10 +148,10 @@
 !UtcTimestamp class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/UtcTimestamp.st,v 1.15 2014-11-26 09:32:11 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/UtcTimestamp.st,v 1.16 2015-06-06 12:42:18 cg Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/UtcTimestamp.st,v 1.15 2014-11-26 09:32:11 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/UtcTimestamp.st,v 1.16 2015-06-06 12:42:18 cg Exp $'
 ! !