Date.st
branchjv
changeset 18457 214d760f8247
parent 18366 a6e62e167c32
parent 18448 47f63bccdee0
child 18569 706dbab4637e
--- 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 $'
 ! !