From 5b05d5335da3212eb5cca280e809ecf9155864c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Czerpak?= Date: Fri, 12 Dec 2025 04:09:11 +0100 Subject: [PATCH] 2025-12-12 04:09 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * include/harbour.hbx * src/harbour.def * src/rtl/dateshb.c + added new PRG function which converts UTC time to local time: hb_UTCToTS( [, @ ) -> * include/hbdate.h * src/harbour.def * src/common/hbdate.c + added new C function which converts UTC time to local time: double hb_timeUTCToLocal( double dTimeStamp, int * piUTCOffset ); --- ChangeLog.txt | 13 +++++++ include/harbour.hbx | 1 + include/hbdate.h | 1 + src/common/hbdate.c | 82 ++++++++++++++++++++++++++++++++++++++++++++- src/harbour.def | 2 ++ src/rtl/dateshb.c | 16 +++++++++ 6 files changed, 114 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 3f5a99ab25..bb37da28dd 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -7,6 +7,19 @@ Entries may not always be in chronological/commit order. See license at the end of file. */ +2025-12-12 04:09 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * include/harbour.hbx + * src/harbour.def + * src/rtl/dateshb.c + + added new PRG function which converts UTC time to local time: + hb_UTCToTS( [, @ ) -> + + * include/hbdate.h + * src/harbour.def + * src/common/hbdate.c + + added new C function which converts UTC time to local time: + double hb_timeUTCToLocal( double dTimeStamp, int * piUTCOffset ); + 2025-12-11 00:15 UTC+0100 Aleksander Czajczynski (hb fki.pl) * src/vm/macro.c * workaround MinGW/GCC 15+ excessive diagnostics in hb_macroTextSymbol() diff --git a/include/harbour.hbx b/include/harbour.hbx index b03b43c700..2adf981172 100644 --- a/include/harbour.hbx +++ b/include/harbour.hbx @@ -922,6 +922,7 @@ DYNAMIC hb_UserName DYNAMIC hb_UStuff DYNAMIC hb_USubStr DYNAMIC hb_UTCOffset +DYNAMIC hb_UTCToTS DYNAMIC hb_utf8Asc DYNAMIC hb_utf8At DYNAMIC hb_utf8Chr diff --git a/include/hbdate.h b/include/hbdate.h index 4267375633..bfdc871eee 100644 --- a/include/hbdate.h +++ b/include/hbdate.h @@ -104,6 +104,7 @@ extern HB_EXPORT void hb_timeStampGet( long * plJulian, long * plMilliSec ); extern HB_EXPORT long hb_timeUTCOffset( void ); /* in seconds */ extern HB_EXPORT double hb_timeLocalToUTC( double dTimeStamp ); +extern HB_EXPORT double hb_timeUTCToLocal( double dTimeStamp, int * piUTCOffset ); extern HB_EXPORT long hb_timeStampUTCOffset( int iYear, int iMonth, int iDay, int iHour, int iMinutes, int iSeconds ); diff --git a/src/common/hbdate.c b/src/common/hbdate.c index 35747b3c28..d0e60f1069 100644 --- a/src/common/hbdate.c +++ b/src/common/hbdate.c @@ -495,7 +495,7 @@ char * hb_timeStr( char * szTime, long lMilliSec ) HB_BOOL hb_timeStrGetUTC( const char * szTime, int * piHour, int * piMinutes, - int * piSeconds, int * piMSec, int *piUTCOffset ) + int * piSeconds, int * piMSec, int * piUTCOffset ) { int iHour, iMinutes, iSeconds, iMSec, iUTCOffset, iBlocks; HB_BOOL fValid; @@ -1180,6 +1180,86 @@ double hb_timeLocalToUTC( double dTimeStamp ) iHour, iMinutes, iSeconds ) / HB_SECONDS_PER_DAY; } +double hb_timeUTCToLocal( double dTimeStamp, int * piUTCOffset ) +{ + double dLocal; + +#if defined( HB_OS_WIN ) + { + typedef BOOL ( WINAPI * P_SYSTEMTIMETOTZSPECIFICLOCALTIME )( LPTIME_ZONE_INFORMATION, LPSYSTEMTIME, LPSYSTEMTIME ); + + static HB_BOOL s_fInit = HB_TRUE; + static P_SYSTEMTIMETOTZSPECIFICLOCALTIME s_pSystemTimeToTzSpecificLocalTime = NULL; + + int iYear, iMonth, iDay, iHour, iMinutes, iSeconds, iMSec; + + hb_timeStampUnpack( dTimeStamp, + &iYear, &iMonth, &iDay, + &iHour, &iMinutes, &iSeconds, &iMSec ); + if( s_fInit ) + { + HMODULE hModule = GetModuleHandle( TEXT( "kernel32" ) ); + if( hModule ) + s_pSystemTimeToTzSpecificLocalTime = ( P_SYSTEMTIMETOTZSPECIFICLOCALTIME ) + HB_WINAPI_GETPROCADDRESS( hModule, "SystemTimeToTzSpecificLocalTime" ); + s_fInit = HB_FALSE; + } + + if( s_pSystemTimeToTzSpecificLocalTime ) + { + SYSTEMTIME lt, st; + + st.wYear = ( WORD ) iYear; + st.wMonth = ( WORD ) iMonth; + st.wDay = ( WORD ) iDay; + st.wHour = ( WORD ) iHour; + st.wMinute = ( WORD ) iMinutes; + st.wSecond = ( WORD ) iSeconds; + st.wMilliseconds = ( WORD ) iMSec; + st.wDayOfWeek = 0; + + if( s_pSystemTimeToTzSpecificLocalTime( NULL, &st, < ) ) + { + dLocal = hb_timeStampPack( lt.wYear, lt.wMonth, lt.wDay, + lt.wHour, lt.wMinute, lt.wSecond, + lt.wMilliseconds ); + } + else + dLocal = dTimeStamp + ( double ) + hb_timeStampUTCOffset( iYear, iMonth, iDay, + iHour, iMinutes, iSeconds ) / HB_SECONDS_PER_DAY; + } + else + dLocal = dTimeStamp + ( double ) + hb_timeStampUTCOffset( iYear, iMonth, iDay, + iHour, iMinutes, iSeconds ) / HB_SECONDS_PER_DAY; + } +#else + { + long lJulian, lMilliSec; + struct tm lt; + time_t utc; + + hb_timeStampUnpackDT( dTimeStamp, &lJulian, &lMilliSec ); + utc = ( time_t ) ( ( lJulian - HB_SYS_DATE_BASE ) * HB_SECONDS_PER_DAY + lMilliSec / 1000 ); +#if defined( HB_HAS_LOCALTIME_R ) + localtime_r( &utc, < ); +#else + lt = *localtime( &utc ); +#endif + lJulian = hb_dateEncode( lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday ); + lMilliSec = hb_timeEncode( lt.tm_hour, lt.tm_min, lt.tm_sec, lMilliSec % 1000 ); + dLocal = hb_timeStampPackDT( lJulian, lMilliSec ); + } +#endif + + if( piUTCOffset ) + *piUTCOffset = ( int ) ( ( dLocal - dTimeStamp ) * HB_SECONDS_PER_DAY + + ( dLocal < dTimeStamp ? -0.5 : 0.5 ) ); + + return dLocal; +} + HB_MAXUINT hb_timerGet( void ) { HB_TRACE( HB_TR_DEBUG, ( "hb_timerGet()" ) ); diff --git a/src/harbour.def b/src/harbour.def index 8558ae0201..00f1722272 100644 --- a/src/harbour.def +++ b/src/harbour.def @@ -1115,6 +1115,7 @@ HB_FUN_HB_USERNAME HB_FUN_HB_USTUFF HB_FUN_HB_USUBSTR HB_FUN_HB_UTCOFFSET +HB_FUN_HB_UTCTOTS HB_FUN_HB_UTF8ASC HB_FUN_HB_UTF8AT HB_FUN_HB_UTF8CHR @@ -3534,6 +3535,7 @@ hb_timeStrGet hb_timeStrGetUTC hb_timeStrRawGet hb_timeUTCOffset +hb_timeUTCToLocal hb_timeUnformat hb_timerGet hb_timerInit diff --git a/src/rtl/dateshb.c b/src/rtl/dateshb.c index 77a38dcd2f..3c1fb41db6 100644 --- a/src/rtl/dateshb.c +++ b/src/rtl/dateshb.c @@ -586,6 +586,7 @@ HB_FUNC( HB_WEEK ) hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } +/* hb_UTCOffset( [ ] ) -> */ HB_FUNC( HB_UTCOFFSET ) { if( HB_ISDATETIME( 1 ) ) @@ -599,6 +600,7 @@ HB_FUNC( HB_UTCOFFSET ) hb_retnl( hb_timeUTCOffset() ); } +/* hb_TSToUTC( ) -> */ HB_FUNC( HB_TSTOUTC ) { if( HB_ISTIMESTAMP( 1 ) ) @@ -606,3 +608,17 @@ HB_FUNC( HB_TSTOUTC ) else hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } + +/* hb_UTCToTS( [, @ ) -> */ +HB_FUNC( HB_UTCTOTS ) +{ + if( HB_ISTIMESTAMP( 1 ) ) + { + int iUTCOffset = 0; + + hb_rettd( hb_timeUTCToLocal( hb_partd( 1 ), &iUTCOffset ) ); + hb_storni( iUTCOffset, 2 ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +}