1919using GxClasses . Helpers ;
2020using System . Net ;
2121#endif
22+ using NodaTime ;
23+ using NodaTime . TimeZones ;
2224using NUglify ;
2325using NUglify . Html ;
2426using GeneXus . Web . Security ;
@@ -2014,6 +2016,11 @@ enum DateFmt
20142016 DMY
20152017 }
20162018
2019+ internal static string LocalTimeZoneId
2020+ {
2021+ get { return DateTimeZoneProviders . Tzdb . GetSystemDefault ( ) . Id ; }
2022+ }
2023+
20172024 public DateTimeUtil ( CultureInfo culture , AMPMFmt amPmFormat )
20182025 {
20192026 cultureInfo = culture ;
@@ -2407,9 +2414,36 @@ static public short CurrentOffset(IGxContext context)
24072414 {
24082415 if ( context == null )
24092416 context = GxContext . Current ;
2417+ #if NODATIME
2418+ TimeSpan ts = CurrentOffset ( context . GetTimeZone ( ) ) ;
2419+ #else
24102420 TimeSpan ts = CurrentOffset ( context . GetOlsonTimeZone ( ) ) ;
2421+ #endif
24112422 return ( short ) ( ts . Hours * 60 + ts . Minutes ) ;
24122423 }
2424+
2425+ static private TimeSpan CurrentOffset ( string clientTimeZone )
2426+ {
2427+ DateTimeZone clientTimeZoneObj = DateTimeZoneProviders . Tzdb [ clientTimeZone ] ;
2428+ if ( clientTimeZoneObj == null )
2429+ clientTimeZoneObj = DateTimeZoneProviders . Tzdb [ LocalTimeZoneId ] ;
2430+ Instant now = SystemClock . Instance . GetCurrentInstant ( ) ;
2431+
2432+ try
2433+ {
2434+ Offset offset = clientTimeZoneObj . GetUtcOffset ( now ) ;
2435+ return offset . ToTimeSpan ( ) ;
2436+ }
2437+ catch ( ArgumentOutOfRangeException )
2438+ {
2439+ Duration oneHour = Duration . FromHours ( 1 ) ;
2440+ Instant oneHourAgo = now . Minus ( oneHour ) ;
2441+ //Avoid InSpringForwardGap/InFallBackRange condition
2442+ Offset offset = clientTimeZoneObj . GetUtcOffset ( oneHourAgo ) ;
2443+ return offset . ToTimeSpan ( ) ;
2444+ }
2445+ }
2446+
24132447 static private TimeSpan CurrentOffset ( OlsonTimeZone clientTimeZone )
24142448 {
24152449 DateTime currentDate = DateTime . Now ;
@@ -2447,11 +2481,20 @@ static DateTime CurrentTimeZoneToUniversalTime(DateTime dt)
24472481 return TimeZone . CurrentTimeZone . ToUniversalTime ( dt ) ;
24482482#endif
24492483 }
2450-
2484+ static DateTime ConvertFromLocal ( DateTime dt , IGxContext context )
2485+ {
2486+ #if NODATIME
2487+ return ConvertDateTime ( DateTime . Now , LocalTimeZoneId , context . GetTimeZone ( ) ) ;
2488+ #else
2489+ OlsonTimeZone fromTimezone = TimeZoneUtil . GetInstanceFromWin32Id ( TimeZoneInfo . Local . Id ) ;
2490+ OlsonTimeZone toTimezone = context . GetOlsonTimeZone ( ) ;
2491+ return ConvertDateTime ( dt , fromTimezone , toTimezone ) ;
2492+ #endif
2493+ }
24512494 static public DateTime Today ( IGxContext context )
24522495 {
24532496 if ( Preferences . useTimezoneFix ( ) )
2454- return ResetMillisecondsTicks ( ResetTime ( ConvertDateTime ( DateTime . Now , TimeZoneUtil . GetInstanceFromWin32Id ( TimeZoneInfo . Local . Id ) , context . GetOlsonTimeZone ( ) ) ) ) ;
2497+ return ResetMillisecondsTicks ( ResetTime ( ConvertFromLocal ( DateTime . Now , context ) ) ) ;
24552498 return ResetMillisecondsTicks ( DateTime . Today ) ;
24562499 }
24572500 static public DateTime Now ( IGxContext context )
@@ -2462,7 +2505,7 @@ static public DateTime Now(IGxContext context)
24622505 static public DateTime NowTicks ( IGxContext context )
24632506 {
24642507 if ( Preferences . useTimezoneFix ( ) )
2465- return ConvertDateTime ( DateTime . Now , TimeZoneUtil . GetInstanceFromWin32Id ( TimeZoneInfo . Local . Id ) , context . GetOlsonTimeZone ( ) ) ;
2508+ return ConvertFromLocal ( DateTime . Now , context ) ;
24662509 return DateTime . Now ;
24672510 }
24682511
@@ -2907,15 +2950,15 @@ static public DateTime ServerNowMs(IGxContext context, IDataStoreProvider dataSt
29072950 if ( dataStore == null )
29082951 return ServerNowMs ( context , new DataStoreHelperBase ( ) . getDataStoreName ( ) ) ;
29092952 if ( Preferences . useTimezoneFix ( ) )
2910- return ResetMicroseconds ( ConvertDateTime ( dataStore . serverNowMs ( ) , TimeZoneUtil . GetInstanceFromWin32Id ( TimeZoneInfo . Local . Id ) , context . GetOlsonTimeZone ( ) ) ) ;
2953+ return ResetMicroseconds ( ConvertFromLocal ( dataStore . serverNowMs ( ) , context ) ) ;
29112954 return ResetMicroseconds ( dataStore . serverNowMs ( ) ) ;
29122955 }
29132956 static public DateTime ServerNow ( IGxContext context , IDataStoreProvider dataStore )
29142957 {
29152958 if ( dataStore == null )
29162959 return ServerNow ( context , new DataStoreHelperBase ( ) . getDataStoreName ( ) ) ;
29172960 if ( Preferences . useTimezoneFix ( ) )
2918- return ResetMillisecondsTicks ( ConvertDateTime ( dataStore . serverNow ( ) , TimeZoneUtil . GetInstanceFromWin32Id ( TimeZoneInfo . Local . Id ) , context . GetOlsonTimeZone ( ) ) ) ;
2961+ return ResetMillisecondsTicks ( ConvertFromLocal ( dataStore . serverNow ( ) , context ) ) ;
29192962 return ResetMillisecondsTicks ( dataStore . serverNow ( ) ) ;
29202963 }
29212964#if ! NETCORE
@@ -2924,13 +2967,13 @@ static public DateTime ServerNow(IGxContext context, IDataStoreProvider dataStor
29242967 static public DateTime ServerNowMs ( IGxContext context , string dataSource )
29252968 {
29262969 if ( Preferences . useTimezoneFix ( ) )
2927- return ResetMicroseconds ( ConvertDateTime ( context . ServerNowMs ( dataSource ) , TimeZoneUtil . GetInstanceFromWin32Id ( TimeZoneInfo . Local . Id ) , context . GetOlsonTimeZone ( ) ) ) ;
2970+ return ResetMicroseconds ( ConvertFromLocal ( context . ServerNowMs ( dataSource ) , context ) ) ;
29282971 return ResetMicroseconds ( context . ServerNowMs ( dataSource ) ) ;
29292972 }
29302973 static public DateTime ServerNow ( IGxContext context , string dataSource )
29312974 {
29322975 if ( Preferences . useTimezoneFix ( ) )
2933- return ResetMillisecondsTicks ( ConvertDateTime ( context . ServerNow ( dataSource ) , TimeZoneUtil . GetInstanceFromWin32Id ( TimeZoneInfo . Local . Id ) , context . GetOlsonTimeZone ( ) ) ) ;
2976+ return ResetMillisecondsTicks ( ConvertFromLocal ( context . ServerNow ( dataSource ) , context ) ) ;
29342977 return ResetMillisecondsTicks ( context . ServerNow ( dataSource ) ) ;
29352978 }
29362979 public static string ServerTime ( IGxContext context , IDataStoreProvider dataStore )
@@ -3107,6 +3150,7 @@ public static string getYYYYMMDDHHMMSSnosep(DateTime date, bool hasMilliseconds)
31073150 if ( hasMilliseconds ) sDate += StringUtil . PadL ( StringUtil . Str ( MilliSecond ( date ) , 3 , 0 ) , 3 , '0' ) ;
31083151 return ( sDate ) ;
31093152 }
3153+
31103154 private static DateTime ConvertDateTime ( DateTime dt , OlsonTimeZone FromTimezone , OlsonTimeZone ToTimezone )
31113155 {
31123156 if ( isNullDate ( dt ) )
@@ -3181,6 +3225,60 @@ public static DateTime DBserver2local(DateTime dt, OlsonTimeZone ClientTimezone)
31813225 throw ex ;
31823226 }
31833227 }
3228+
3229+ private static DateTime ConvertDateTime ( DateTime dt , string fromTimezone , string toTimezone )
3230+ {
3231+ if ( isNullDate ( dt ) )
3232+ return dt ;
3233+
3234+ DateTimeZone toZone ;
3235+
3236+ if ( string . IsNullOrEmpty ( toTimezone ) || DateTimeZoneProviders . Tzdb [ toTimezone ] == null )
3237+ toZone = DateTimeZoneProviders . Tzdb . GetSystemDefault ( ) ;
3238+ else
3239+ toZone = DateTimeZoneProviders . Tzdb [ toTimezone ] ;
3240+
3241+ LocalDateTime dtLocal = LocalDateTime . FromDateTime ( dt ) ;
3242+ DateTimeZone fromZone = DateTimeZoneProviders . Tzdb [ fromTimezone ] ;
3243+ ZonedDateTime fromZoned = dtLocal . InZoneLeniently ( fromZone ) ;
3244+
3245+ ZonedDateTime toZoned = fromZoned . WithZone ( toZone ) ;
3246+ return toZoned . LocalDateTime . ToDateTimeUnspecified ( ) ;
3247+ }
3248+ internal static DateTime Local2DBserver ( DateTime dt , string clientTimezone )
3249+ {
3250+ try
3251+ {
3252+ Preferences . StorageTimeZonePty storagePty = Preferences . getStorageTimezonePty ( ) ;
3253+ if ( clientTimezone == null || isNullDate ( dt ) || storagePty == Preferences . StorageTimeZonePty . Undefined )
3254+ return dt ;
3255+ string toTimezone = ( storagePty == Preferences . StorageTimeZonePty . Utc ) ? DateTimeZone . Utc . Id : LocalTimeZoneId ;
3256+ return ConvertDateTime ( dt , clientTimezone , toTimezone ) ;
3257+
3258+ }
3259+ catch ( Exception ex )
3260+ {
3261+ GXLogging . Error ( log , ex , "Local2DBserver error" ) ;
3262+ throw ex ;
3263+ }
3264+ }
3265+ public static DateTime DBserver2local ( DateTime dt , string clientTimezone )
3266+ {
3267+ try
3268+ {
3269+ Preferences . StorageTimeZonePty storagePty = Preferences . getStorageTimezonePty ( ) ;
3270+ if ( clientTimezone == null || isNullDate ( dt ) || storagePty == Preferences . StorageTimeZonePty . Undefined )
3271+ return dt ;
3272+ string fromTimezone = ( storagePty == Preferences . StorageTimeZonePty . Utc ) ? DateTimeZone . Utc . Id : LocalTimeZoneId ;
3273+ return ConvertDateTime ( dt , fromTimezone , clientTimezone ) ;
3274+ }
3275+ catch ( Exception ex )
3276+ {
3277+ GXLogging . Error ( log , ex , "DBserver2local error" ) ;
3278+ throw ex ;
3279+ }
3280+ }
3281+
31843282 public static string FormatDateTimeParmMS ( DateTime date )
31853283 {
31863284 if ( date . Equals ( nullDate ) )
@@ -3268,6 +3366,21 @@ public static DateTime getTimeAsDate(long ticks)
32683366 {
32693367 return new DateTime ( datetTime1970 . Ticks + ticks * timeConversionFactor ) ;
32703368 }
3369+ static private DateTime fromUniversalTime ( DateTime dt , string toTimezone )
3370+ {
3371+ DateTimeZone toTimeZone = DateTimeZoneProviders . Tzdb [ toTimezone ] ;
3372+ Instant instant = Instant . FromDateTimeUtc ( dt ) ;
3373+ ZonedDateTime zonedDateTime = instant . InZone ( toTimeZone ) ;
3374+ return zonedDateTime . ToDateTimeUnspecified ( ) ;
3375+ }
3376+ static private DateTime toUniversalTime ( DateTime dt , string fromTimezone )
3377+ {
3378+ DateTimeZone localZone = DateTimeZoneProviders . Tzdb [ fromTimezone ] ;
3379+ ZonedDateTime localDateTime = LocalDateTime . FromDateTime ( dt ) . InZoneLeniently ( localZone ) ;
3380+ ZonedDateTime utcDateTime = localDateTime . ToInstant ( ) . InUtc ( ) ;
3381+ return utcDateTime . ToDateTimeUtc ( ) ;
3382+ }
3383+
32713384 static private DateTime fromUniversalTime ( DateTime dt , OlsonTimeZone ToTimezone )
32723385 {
32733386
@@ -3354,25 +3467,41 @@ static private bool isNullDateCompatible(DateTime dt)
33543467
33553468 static public DateTime fromUniversalTime ( DateTime dt )
33563469 {
3470+ #if NODATIME
3471+ return isNullDateCompatible ( dt ) ? dt : fromUniversalTime ( dt , GxContext . Current . GetTimeZone ( ) ) ;
3472+ #else
33573473 return isNullDateCompatible ( dt ) ? dt : fromUniversalTime ( dt , GxContext . Current . GetOlsonTimeZone ( ) ) ;
3474+ #endif
33583475 }
33593476
33603477 static public DateTime toUniversalTime ( DateTime dt )
33613478 {
3479+ #if NODATIME
3480+ return isNullDateCompatible ( dt ) ? dt : toUniversalTime ( dt , GxContext . Current . GetTimeZone ( ) ) ;
3481+ #else
33623482 return isNullDateCompatible ( dt ) ? dt : toUniversalTime ( dt , GxContext . Current . GetOlsonTimeZone ( ) ) ;
3483+ #endif
33633484 }
33643485
33653486 static public DateTime toUniversalTime ( DateTime dt , IGxContext context )
33663487 {
3488+ #if NODATIME
3489+ return isNullDateCompatible ( dt ) ? dt : toUniversalTime ( dt , context . GetTimeZone ( ) ) ;
3490+ #else
33673491 return isNullDateCompatible ( dt ) ? dt : toUniversalTime ( dt , context . GetOlsonTimeZone ( ) ) ;
3492+ #endif
33683493 }
33693494
33703495 static public DateTime FromTimeZone ( DateTime dt , String sTZ , IGxContext context )
33713496 {
3497+ #if NODATIME
3498+ return ConvertDateTime ( dt , sTZ , context . GetTimeZone ( ) ) ;
3499+ #else
33723500 OlsonTimeZone fromTimeZone = TimeZoneUtil . GetInstanceFromOlsonName ( sTZ ) ;
33733501 if ( fromTimeZone != null )
33743502 return ConvertDateTime ( dt , fromTimeZone , context . GetOlsonTimeZone ( ) ) ;
33753503 return dt ;
3504+ #endif
33763505 }
33773506
33783507 }
0 commit comments