@@ -45,10 +45,20 @@ namespace
45
45
public:
46
46
TimeZoneDesc (MemoryPool& pool)
47
47
: asciiName(pool),
48
- unicodeName (pool)
48
+ unicodeName (pool),
49
+ icuCachedCalendar(nullptr )
49
50
{
50
51
}
51
52
53
+ ~TimeZoneDesc ()
54
+ {
55
+ if (const auto calendar = icuCachedCalendar.exchange (nullptr ))
56
+ {
57
+ auto & icuLib = Jrd::UnicodeUtil::getConversionICU ();
58
+ icuLib.ucalClose (calendar);
59
+ }
60
+ }
61
+
52
62
public:
53
63
void setName (const char * name)
54
64
{
@@ -70,9 +80,21 @@ namespace
70
80
return unicodeName.begin ();
71
81
}
72
82
83
+ IcuCalendarWrapper getCalendar (const Jrd::UnicodeUtil::ConversionICU& icuLib, UErrorCode* err = nullptr ) const
84
+ {
85
+ auto calendar = icuCachedCalendar.exchange (nullptr );
86
+ UErrorCode internalErr = U_ZERO_ERROR;
87
+
88
+ if (!calendar)
89
+ calendar = icuLib.ucalOpen (getUnicodeName (), -1 , nullptr , UCAL_GREGORIAN, (err ? err : &internalErr));
90
+
91
+ return IcuCalendarWrapper (calendar, &icuCachedCalendar);
92
+ }
93
+
73
94
private:
74
95
string asciiName;
75
96
Array<UChar> unicodeName;
97
+ mutable std::atomic<UCalendar*> icuCachedCalendar;
76
98
};
77
99
}
78
100
@@ -593,30 +615,21 @@ void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, SSHORT* of
593
615
594
616
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU ();
595
617
596
- UCalendar* icuCalendar = icuLib.ucalOpen (
597
- getDesc (timeStampTz.time_zone )->getUnicodeName (), -1 , NULL , UCAL_GREGORIAN, &icuErrorCode);
618
+ auto icuCalendar = getDesc (timeStampTz.time_zone )->getCalendar (icuLib, &icuErrorCode);
598
619
599
620
if (!icuCalendar)
600
621
status_exception::raise (Arg::Gds (isc_random) << " Error calling ICU's ucal_open." );
601
622
602
623
icuLib.ucalSetMillis (icuCalendar, timeStampToIcuDate (timeStampTz.utc_timestamp ), &icuErrorCode);
603
624
604
625
if (U_FAILURE (icuErrorCode))
605
- {
606
- icuLib.ucalClose (icuCalendar);
607
626
status_exception::raise (Arg::Gds (isc_random) << " Error calling ICU's ucal_setMillis." );
608
- }
609
627
610
628
displacement = (icuLib.ucalGet (icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) +
611
629
icuLib.ucalGet (icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE;
612
630
613
631
if (U_FAILURE (icuErrorCode))
614
- {
615
- icuLib.ucalClose (icuCalendar);
616
632
status_exception::raise (Arg::Gds (isc_random) << " Error calling ICU's ucal_get." );
617
- }
618
-
619
- icuLib.ucalClose (icuCalendar);
620
633
}
621
634
622
635
*offset = displacement;
@@ -702,8 +715,7 @@ void TimeZoneUtil::localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz)
702
715
703
716
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU ();
704
717
705
- UCalendar* icuCalendar = icuLib.ucalOpen (
706
- getDesc (timeStampTz.time_zone )->getUnicodeName (), -1 , NULL , UCAL_GREGORIAN, &icuErrorCode);
718
+ auto icuCalendar = getDesc (timeStampTz.time_zone )->getCalendar (icuLib, &icuErrorCode);
707
719
708
720
if (!icuCalendar)
709
721
status_exception::raise (Arg::Gds (isc_random) << " Error calling ICU's ucal_open." );
@@ -715,21 +727,13 @@ void TimeZoneUtil::localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz)
715
727
times.tm_hour , times.tm_min , times.tm_sec , &icuErrorCode);
716
728
717
729
if (U_FAILURE (icuErrorCode))
718
- {
719
- icuLib.ucalClose (icuCalendar);
720
730
status_exception::raise (Arg::Gds (isc_random) << " Error calling ICU's ucal_setDateTime." );
721
- }
722
731
723
732
displacement = (icuLib.ucalGet (icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) +
724
733
icuLib.ucalGet (icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE;
725
734
726
735
if (U_FAILURE (icuErrorCode))
727
- {
728
- icuLib.ucalClose (icuCalendar);
729
736
status_exception::raise (Arg::Gds (isc_random) << " Error calling ICU's ucal_get." );
730
- }
731
-
732
- icuLib.ucalClose (icuCalendar);
733
737
}
734
738
735
739
const auto ticks = TimeStamp::timeStampToTicks (timeStampTz.utc_timestamp ) -
@@ -771,30 +775,21 @@ bool TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmt
771
775
#endif
772
776
Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU ();
773
777
774
- UCalendar* icuCalendar = icuLib.ucalOpen (
775
- getDesc (timeStampTz.time_zone )->getUnicodeName (), -1 , NULL , UCAL_GREGORIAN, &icuErrorCode);
778
+ auto icuCalendar = getDesc (timeStampTz.time_zone )->getCalendar (icuLib, &icuErrorCode);
776
779
777
780
if (!icuCalendar)
778
781
status_exception::raise (Arg::Gds (isc_random) << " Error calling ICU's ucal_open." );
779
782
780
783
icuLib.ucalSetMillis (icuCalendar, timeStampToIcuDate (timeStampTz.utc_timestamp ), &icuErrorCode);
781
784
782
785
if (U_FAILURE (icuErrorCode))
783
- {
784
- icuLib.ucalClose (icuCalendar);
785
786
status_exception::raise (Arg::Gds (isc_random) << " Error calling ICU's ucal_setMillis." );
786
- }
787
787
788
788
displacement = (icuLib.ucalGet (icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) +
789
789
icuLib.ucalGet (icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE;
790
790
791
791
if (U_FAILURE (icuErrorCode))
792
- {
793
- icuLib.ucalClose (icuCalendar);
794
792
status_exception::raise (Arg::Gds (isc_random) << " Error calling ICU's ucal_get." );
795
- }
796
-
797
- icuLib.ucalClose (icuCalendar);
798
793
}
799
794
catch (const Exception&)
800
795
{
@@ -1063,12 +1058,11 @@ ISC_TIMESTAMP_TZ TimeZoneUtil::dateToTimeStampTz(const ISC_DATE& date, Callbacks
1063
1058
TimeZoneRuleIterator::TimeZoneRuleIterator (USHORT aId, const ISC_TIMESTAMP_TZ& aFrom, const ISC_TIMESTAMP_TZ& aTo)
1064
1059
: id(aId),
1065
1060
icuLib(Jrd::UnicodeUtil::getConversionICU()),
1066
- toTicks(TimeStamp::timeStampToTicks(aTo.utc_timestamp))
1061
+ toTicks(TimeStamp::timeStampToTicks(aTo.utc_timestamp)),
1062
+ icuCalendar(getDesc(aId)->getCalendar(icuLib))
1067
1063
{
1068
1064
UErrorCode icuErrorCode = U_ZERO_ERROR;
1069
1065
1070
- icuCalendar = icuLib.ucalOpen (getDesc (id)->getUnicodeName (), -1 , NULL , UCAL_GREGORIAN, &icuErrorCode);
1071
-
1072
1066
if (!icuCalendar)
1073
1067
status_exception::raise (Arg::Gds (isc_random) << " Error calling ICU's ucal_open." );
1074
1068
@@ -1105,11 +1099,6 @@ TimeZoneRuleIterator::TimeZoneRuleIterator(USHORT aId, const ISC_TIMESTAMP_TZ& a
1105
1099
startTicks = TimeStamp::timeStampToTicks (TimeZoneUtil::icuDateToTimeStamp (icuDate));
1106
1100
}
1107
1101
1108
- TimeZoneRuleIterator::~TimeZoneRuleIterator ()
1109
- {
1110
- icuLib.ucalClose (icuCalendar);
1111
- }
1112
-
1113
1102
bool TimeZoneRuleIterator::next ()
1114
1103
{
1115
1104
if (startTicks > toTicks)
0 commit comments