1717package za .co .absa .standardization .time
1818
1919import za .co .absa .standardization .implicits .StringImplicits .StringEnhancements
20+ import za .co .absa .standardization .time .DateTimePattern .{patternMicroSecondChar , patternMilliSecondChar , patternNanoSecondChat }
2021import za .co .absa .standardization .types .{Section , TypePattern }
2122
2223/**
@@ -29,10 +30,12 @@ abstract sealed class DateTimePattern(pattern: String, isDefault: Boolean = fals
2930 extends TypePattern (pattern, isDefault){
3031
3132 val isEpoch : Boolean
33+ val isCentury : Boolean
3234 val epochFactor : Long
3335
3436 val timeZoneInPattern : Boolean
3537 val defaultTimeZone : Option [String ]
38+ val originalPattern : Option [String ]
3639 val isTimeZoned : Boolean
3740
3841 val millisecondsPosition : Option [Section ]
@@ -47,7 +50,6 @@ abstract sealed class DateTimePattern(pattern: String, isDefault: Boolean = fals
4750 val q = " \" "
4851 s " pattern: $q$pattern$q" + defaultTimeZone.map(x => s " (default time zone: $q$x$q) " ).getOrElse(" " )
4952 }
50-
5153}
5254
5355object DateTimePattern {
@@ -57,6 +59,8 @@ object DateTimePattern {
5759 val EpochMicroKeyword = " epochmicro"
5860 val EpochNanoKeyword = " epochnano"
5961
62+ val patternCenturyChar = " c"
63+
6064 private val epochUnitFactor = 1
6165 private val epoch1kFactor = 1000
6266 private val epoch1MFactor = 1000000
@@ -81,10 +85,12 @@ object DateTimePattern {
8185 extends DateTimePattern (pattern, isDefault) {
8286
8387 override val isEpoch : Boolean = true
88+ override val isCentury : Boolean = false
8489 override val epochFactor : Long = DateTimePattern .epochFactor(pattern)
8590
8691 override val timeZoneInPattern : Boolean = true
8792 override val defaultTimeZone : Option [String ] = None
93+ override val originalPattern : Option [String ] = None
8894 override val isTimeZoned : Boolean = true
8995
9096 override val millisecondsPosition : Option [Section ] = pattern match {
@@ -111,9 +117,9 @@ object DateTimePattern {
111117 override val patternWithoutSecondFractions : String = EpochKeyword
112118 }
113119
114- private final case class StandardDTPattern (override val pattern : String ,
115- assignedDefaultTimeZone : Option [String ] = None ,
116- override val isDefault : Boolean = false )
120+ private abstract class StandardDTPatternBase (override val pattern : String ,
121+ assignedDefaultTimeZone : Option [String ],
122+ override val isDefault : Boolean = false )
117123 extends DateTimePattern (pattern, isDefault) {
118124
119125 override val isEpoch : Boolean = false
@@ -143,22 +149,47 @@ object DateTimePattern {
143149 }
144150 }
145151
146- private def create (pattern : String , assignedDefaultTimeZone : Option [String ], isDefault : Boolean ): DateTimePattern = {
152+ private final case class StandardDTPattern (override val pattern : String ,
153+ assignedDefaultTimeZone : Option [String ] = None ,
154+ override val isDefault : Boolean = false )
155+ extends StandardDTPatternBase (pattern, assignedDefaultTimeZone, isDefault) {
156+
157+ override val isCentury : Boolean = false
158+ override val originalPattern : Option [String ] = None
159+ }
160+
161+ private final case class CenturyDTPattern (override val pattern : String ,
162+ override val originalPattern : Option [String ],
163+ assignedDefaultTimeZone : Option [String ] = None ,
164+ override val isDefault : Boolean = false )
165+ extends StandardDTPatternBase (pattern, assignedDefaultTimeZone, isDefault) {
166+
167+ override val isCentury : Boolean = true
168+ }
169+
170+ private def create (pattern : String ,
171+ assignedDefaultTimeZone : Option [String ],
172+ isCenturyPattern : Boolean ,
173+ isDefault : Boolean ): DateTimePattern = {
147174 if (isEpoch(pattern)) {
148175 EpochDTPattern (pattern, isDefault)
176+ } else if (isCenturyPattern && isCentury(pattern)) {
177+ val patternWithoutCentury = pattern.replaceAll(patternCenturyChar, " yy" )
178+ CenturyDTPattern (patternWithoutCentury, Some (pattern), assignedDefaultTimeZone, isDefault)
149179 } else {
150180 StandardDTPattern (pattern, assignedDefaultTimeZone, isDefault)
151181 }
152182 }
153183
154184 def apply (pattern : String ,
155- assignedDefaultTimeZone : Option [String ] = None ): DateTimePattern = {
156- create(pattern, assignedDefaultTimeZone, isDefault = false )
185+ assignedDefaultTimeZone : Option [String ] = None ,
186+ isCenturyPattern : Boolean = false ): DateTimePattern = {
187+ create(pattern, assignedDefaultTimeZone, isCenturyPattern, isDefault = false )
157188 }
158189
159190 def asDefault (pattern : String ,
160191 assignedDefaultTimeZone : Option [String ] = None ): DateTimePattern = {
161- create(pattern, assignedDefaultTimeZone, isDefault = true )
192+ create(pattern, assignedDefaultTimeZone, isCenturyPattern = false , isDefault = true )
162193 }
163194
164195 def isEpoch (pattern : String ): Boolean = {
@@ -168,6 +199,10 @@ object DateTimePattern {
168199 }
169200 }
170201
202+ def isCentury (pattern : String ): Boolean = {
203+ pattern.contains(s " ${patternCenturyChar}yy " )
204+ }
205+
171206 def epochFactor (pattern : String ): Long = {
172207 pattern.toLowerCase match {
173208 case EpochKeyword => epochUnitFactor
0 commit comments