4 Функции для работы с датой и временем
7 Copyright (c) 1996 Eugene Roshal
8 Copyright (c) 2000 Far Group
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions
14 1. Redistributions of source code must retain the above copyright
15 notice, this list of conditions and the following disclaimer.
16 2. Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in the
18 documentation and/or other materials provided with the distribution.
19 3. The name of the authors may not be used to endorse or promote products
20 derived from this software without specific prior written permission.
22 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "headers.hpp"
37 #include "datetime.hpp"
39 #include "language.hpp"
43 #define range(low,item,hi) Max(low,Min(item,hi))
45 static FARString AMonth
[2][12], AWeekday
[2][7],Month
[2][12],Weekday
[2][7];
47 static int CurLang
=-1, WeekFirst
=0;
49 DWORD
ConvertYearToFull(DWORD ShortYear
)
51 DWORD UpperBoundary
= 0;
52 // if(!GetCalendarInfo(LOCALE_USER_DEFAULT, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX|CAL_RETURN_NUMBER, nullptr, 0, &UpperBoundary))
54 UpperBoundary
= 2029; // Magic, current default value.
56 return (UpperBoundary
/100-(ShortYear
<UpperBoundary
%100?0:1))*100+ShortYear
;
62 // GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_IDATE|LOCALE_RETURN_NUMBER,reinterpret_cast<LPWSTR>(&Result),sizeof(Result)/sizeof(WCHAR));
66 wchar_t GetDateSeparator()
69 // GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SDATE,Info,ARRAYSIZE(Info));
74 wchar_t GetTimeSeparator()
77 // GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STIME,Info,ARRAYSIZE(Info));
82 void PrepareStrFTime()
84 //DWORD Loc[]={LANG_ENGLISH,LANG_NEUTRAL},ID;
86 // GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_IFIRSTDAYOFWEEK|LOCALE_RETURN_NUMBER,reinterpret_cast<LPWSTR>(&WeekFirst),sizeof(WeekFirst)/sizeof(WCHAR));
88 for (int i
=0; i
<2; i
++)
90 const wchar_t *months
[12] = {L
"January", L
"February", L
"March", L
"April", L
"May", L
"June", L
"July", L
"August", L
"September", L
"October", L
"November", L
"December"};
91 const wchar_t *amonths
[12] = {L
"Jan", L
"Feb", L
"Mar", L
"Apr", L
"May", L
"Jun", L
"Jul", L
"Aug", L
"Sep", L
"Oct", L
"Nov", L
"Dec"};
92 for (int j
= 0; j
<12; ++j
) {
93 Month
[i
][j
] = months
[j
];
94 AMonth
[i
][j
] = amonths
[j
];
97 const wchar_t *days
[7] = {L
"Monday", L
"Tuesday", L
"Wednesday", L
"Thursday", L
"Friday", L
"Saturday", L
"Sunday"};
98 const wchar_t *adays
[7] = {L
"Mon", L
"Tue", L
"Wed", L
"Thu", L
"Fri", L
"Sat", L
"Sun"};
99 for (int j
= 0; j
<7; ++j
) {
100 Weekday
[i
][j
] = days
[j
];
101 AWeekday
[i
][j
] = adays
[j
];
103 /* LCID CurLCID=MAKELCID(MAKELANGID(Loc[i],SUBLANG_DEFAULT),SORT_DEFAULT);
105 for (ID=LOCALE_SMONTHNAME1; ID<=LOCALE_SMONTHNAME12; ID++)
107 int size=GetLocaleInfo(CurLCID,ID,nullptr,0);
108 LPWSTR lpwszTemp=Month[i][ID-LOCALE_SMONTHNAME1].GetBuffer(size);
109 GetLocaleInfo(CurLCID,ID,lpwszTemp,size);
110 *lpwszTemp=Upper(*lpwszTemp);
111 Month[i][ID-LOCALE_SMONTHNAME1].ReleaseBuffer();
114 for (ID=LOCALE_SABBREVMONTHNAME1; ID<=LOCALE_SABBREVMONTHNAME12; ID++)
116 int size=GetLocaleInfo(CurLCID,ID,nullptr,0);
117 LPWSTR lpwszTemp=AMonth[i][ID-LOCALE_SABBREVMONTHNAME1].GetBuffer(size);
118 GetLocaleInfo(CurLCID,ID,lpwszTemp,size);
119 *lpwszTemp=Upper(*lpwszTemp);
120 AMonth[i][ID-LOCALE_SABBREVMONTHNAME1].ReleaseBuffer();
123 for (ID=LOCALE_SDAYNAME1; ID<=LOCALE_SDAYNAME7; ID++)
125 int size=GetLocaleInfo(CurLCID,ID,nullptr,0);
126 LPWSTR lpwszTemp=Weekday[i][ID-LOCALE_SDAYNAME1].GetBuffer(size);
127 GetLocaleInfo(CurLCID,ID,lpwszTemp,size);
128 *lpwszTemp=Upper(*lpwszTemp);
129 Weekday[i][ID-LOCALE_SDAYNAME1].ReleaseBuffer();
132 for (ID=LOCALE_SABBREVDAYNAME1; ID<=LOCALE_SABBREVDAYNAME7; ID++)
134 int size=GetLocaleInfo(CurLCID,ID,nullptr,0);
135 LPWSTR lpwszTemp=AWeekday[i][ID-LOCALE_SABBREVDAYNAME1].GetBuffer(size);
136 GetLocaleInfo(CurLCID,ID,lpwszTemp,size);
137 *lpwszTemp=Upper(*lpwszTemp);
138 AWeekday[i][ID-LOCALE_SABBREVDAYNAME1].ReleaseBuffer();
146 static void atime(FARString
&strDest
, const tm
*tmPtr
)
148 // Thu Oct 07 12:37:32 1999
149 strDest
.Format(L
"%ls %ls %02d %02d:%02d:%02d %4d",
150 AWeekday
[CurLang
][!WeekFirst
?((tmPtr
->tm_wday
+6)%7):(!(tmPtr
->tm_wday
)?6:tmPtr
->tm_wday
-1)].CPtr(),
151 AMonth
[CurLang
][tmPtr
->tm_mon
].CPtr(),
156 tmPtr
->tm_year
+1900);
159 static void st_time(FARString
&strDest
,const tm
*tmPtr
,const wchar_t chr
)
161 int DateSeparator
=GetDateSeparator();
165 strDest
.Format(L
"%2d-%3.3ls-%4d",range(1,tmPtr
->tm_mday
,31),AMonth
[CurLang
][range(0, tmPtr
->tm_mon
,11)].CPtr(),tmPtr
->tm_year
+1900);
168 else switch (GetDateFormat())
171 strDest
.Format(L
"%02d%lc%02d%lc%4d",
176 tmPtr
->tm_year
+1900);
179 strDest
.Format(L
"%02d%lc%02d%lc%4d",
184 tmPtr
->tm_year
+1900);
187 strDest
.Format(L
"%4d%lc%02d%lc%02d",
197 // weeknumber --- figure how many weeks into the year
198 static int weeknumber(const tm
*timeptr
,const int firstweekday
)
200 int wday
=timeptr
->tm_wday
;
210 int ret
=((timeptr
->tm_yday
+7-wday
)/7);
218 // isleap --- is a year a leap year?
219 static int isleap(const int year
)
221 return ((!(year
%4)&&(year
%100))||!(year
%400));
224 static int iso8601wknum(const tm
*timeptr
)
228 * If the week (Monday to Sunday) containing January 1
229 * has four or more days in the new year, then it is week 1;
230 * otherwise it is the highest numbered week of the previous
231 * year (52 or 53), and the next week is week 1.
233 * ADR: This means if Jan 1 was Monday through Thursday,
234 * it was week 1, otherwise week 52 or 53.
236 * XPG4 erroneously included POSIX.2 rationale text in the
237 * main body of the standard. Thus it requires week 53.
239 // get week number, Monday as first day of the week
240 int weeknum
=weeknumber(timeptr
,1);
242 * With thanks and tip of the hatlo to tml@tik.vtt.fi
244 * What day of the week does January 1 fall on?
246 * (timeptr->tm_yday - jan1.tm_yday) MOD 7 ==
247 * (timeptr->tm_wday - jan1.tm_wday) MOD 7
251 * timeptr->tm_wday MOD 7 == timeptr->tm_wday
252 * from which it follows that. . .
254 int jan1day
=timeptr
->tm_wday
-(timeptr
->tm_yday
%7);
260 * If Jan 1 was a Monday through Thursday, it was in
261 * week 1. Otherwise it was last year's highest week, which is
262 * this year's week 0.
264 * What does that mean?
265 * If Jan 1 was Monday, the week number is exactly right, it can
267 * If it was Tuesday through Thursday, the weeknumber is one
268 * less than it should be, so we add one.
269 * Otherwise, Friday, Saturday or Sunday, the week number is
270 * OK, but if it is 0, it needs to be 52 or 53.
287 #ifdef USE_BROKEN_XPG4
288 /* XPG4 (as of March 1994) says 53 unconditionally */
291 // get week number of last week of last year
297 dec31ly
.tm_wday
=!jan1day
?6:jan1day
-1;
298 dec31ly
.tm_yday
=364+isleap(dec31ly
.tm_year
+1900);
299 weeknum
=iso8601wknum(&dec31ly
);
306 if (timeptr
->tm_mon
==11)
309 * The last week of the year
310 * can be in week 1 of next year.
313 * This can only happen if
319 if ((timeptr
->tm_wday
==1&&(timeptr
->tm_mday
>=29&&timeptr
->tm_mday
<=31))||
320 (timeptr
->tm_wday
==2&&(timeptr
->tm_mday
==30||timeptr
->tm_mday
==31))||
321 (timeptr
->tm_wday
==3&&timeptr
->tm_mday
==31))
328 size_t WINAPI
StrFTime(FARString
&strDest
, const wchar_t *Format
,const tm
*t
)
330 if (CurLang
==-1 && Lang
.IsLanguageLoaded())
337 for (Len
=1; *Format
; Format
++)
342 const wchar_t Text
[]={*Format
,0};
355 // Краткое имя дня недели (Sun,Mon,Tue,Wed,Thu,Fri,Sat)
356 // abbreviated weekday name
358 strBuf
=AWeekday
[CurLang
][!WeekFirst
?((t
->tm_wday
+6)%7):(!t
->tm_wday
?6:t
->tm_wday
-1)];
360 // Полное имя дня недели
363 strBuf
=Weekday
[CurLang
][!WeekFirst
?((t
->tm_wday
+6)%7):(!t
->tm_wday
?6:t
->tm_wday
-1)];
365 // Краткое имя месяца (Jan,Feb,...)
366 // abbreviated month name
369 strBuf
=AMonth
[CurLang
][t
->tm_mon
];
374 strBuf
=Month
[CurLang
][t
->tm_mon
];
376 //Дата и время в формате WDay Mnt Day HH:MM:SS yyyy
377 //appropriate date and time representation
381 // Столетие как десятичное число (00 - 99). Например, 1992 => 19
383 strBuf
.Format(L
"%02d",(t
->tm_year
+1900)/100);
385 // day of month, blank padded
387 // Две цифры дня месяца (01 - 31)
388 // day of the month, 01 - 31
390 strBuf
.Format(*Format
==L
'e'?L
"%2d":L
"%02d",t
->tm_mday
);
392 // hour, 24-hour clock, blank pad
394 // Две цифры часа (00 - 23)
395 // hour, 24-hour clock, 00 - 23
397 strBuf
.Format(*Format
==L
'k'?L
"%2d":L
"%02d",t
->tm_hour
);
399 // hour, 12-hour clock, 1 - 12, blank pad
401 // Две цифры часа (01 - 12)
402 // hour, 12-hour clock, 01 - 12
410 strBuf
.Format(*Format
==L
'l'?L
"%2d":L
"%02d",I
);
413 // Три цифры дня в году (001 - 366)
414 // day of the year, 001 - 366
416 strBuf
.Format(L
"%03d",t
->tm_yday
+1);
418 // Две цифры месяца, как десятичное число (1 - 12)
422 // %mh - Hex month digit
424 const wchar_t *fmt
=Format
[1]==L
'h'?L
"%X":Format
[1]==L
'0'?L
"%02d":L
"%d";
429 strBuf
.Format(fmt
,t
->tm_mon
+1);
432 // Две цифры минут (00 - 59)
435 strBuf
.Format(L
"%02d",t
->tm_min
);
438 // am or pm based on 12-hour clock
440 strBuf
=(t
->tm_hour
/12)?L
"PM":L
"AM";
442 // Две цифры секунд (00 - 59)
445 strBuf
.Format(L
"%02d",t
->tm_sec
);
447 // День недели где 0 - Воскресенье (Sunday) (0 - 6)
448 // weekday, Sunday == 0, 0 - 6
450 strBuf
.Format(L
"%d",t
->tm_wday
);
452 // Две цифры номера недели, где Воскресенье (Sunday)
453 // является первым днем недели (00 - 53)
454 // week of year, Sunday is first day of week
456 // Две цифры номера недели, где Понедельник (Monday)
457 // является первым днем недели (00 - 53)
458 // week of year, Monday is first day of week
461 int I
=t
->tm_wday
-(t
->tm_yday
%7);
463 //I = (chr == 'W'?(!WeekFirst?((t->tm_wday+6)%7):(t->tm_wday? t->tm_wday-1:6)):(t->tm_wday)) - (t->tm_yday % 7);
467 strBuf
.Format(L
"%02d",(t
->tm_yday
+I
-(*Format
==L
'W'))/7);
470 // date as dd-bbb-YYYY
472 // Дата в формате mm.dd.yyyy
473 // appropriate date representation
476 st_time(strBuf
,t
,*Format
);
478 // Время в формате HH:MM:SS
479 // appropriate time representation
483 int TimeSeparator
=GetTimeSeparator();
484 strBuf
.Format(L
"%02d%c%02d%c%02d",t
->tm_hour
,TimeSeparator
,t
->tm_min
,TimeSeparator
,t
->tm_sec
);
487 // Две цифры года без столетия (00 to 99)
488 // year without a century, 00 - 99
490 strBuf
.Format(L
"%02d",t
->tm_year
%100);
492 // Год со столетием (19yy-20yy)
495 strBuf
.Format(L
"%d",1900+t
->tm_year
);
497 // Имя часового пояса или пусто, если часовой пояс не задан
499 //todo strBuf.Format(L"%+03d%02d",-(_timezone/3600),-(_timezone/60)%60);
500 //Ptr = _tzname[ t->tm_isdst ];
513 // time as %I:%M:%S %p
515 StrFTime(strBuf
,L
"%I:%M:%S %p",t
);
519 StrFTime(strBuf
,L
"%H:%M",t
);
521 // week of year according ISO 8601
523 strBuf
.Format(L
"%02d",iso8601wknum(t
));
528 Len
+=strBuf
.GetLength();
539 size_t MkStrFTime(FARString
&strDest
, const wchar_t *Fmt
)
545 time_now
=localtime(&secs_now
);
548 Fmt
=Opt
.Macro
.strDateFormat
;
550 return StrFTime(strDest
,Fmt
,time_now
);
553 int64_t FileTimeDifference(const FILETIME
*a
, const FILETIME
* b
)
555 LARGE_INTEGER A
={{a
->dwLowDateTime
, (LONG
)a
->dwHighDateTime
}},B
={{b
->dwLowDateTime
, (LONG
)b
->dwHighDateTime
}};
556 return A
.QuadPart
- B
.QuadPart
;
559 uint64_t FileTimeToUI64(const FILETIME
*ft
)
561 ULARGE_INTEGER A
={{ft
->dwLowDateTime
,ft
->dwHighDateTime
}};
565 void GetFileDateAndTime(const wchar_t *Src
,LPWORD Dst
,size_t Count
,int Separator
)
567 for (size_t i
=0; i
<Count
; i
++)
573 const wchar_t *Ptr
=Src
;
575 for (size_t i
=0; i
<Count
; i
++)
577 Ptr
=GetCommaWord(Ptr
,strDigit
,Separator
);
581 const wchar_t *PtrDigit
=strDigit
;
583 while (*PtrDigit
&&!isdigit(*PtrDigit
))//todo iswdigit
590 Dst
[i
]=static_cast<WORD
>(_wtoi(PtrDigit
));
600 void StrToDateTime(const wchar_t *CDate
, const wchar_t *CTime
, FILETIME
&ft
, int DateFormat
, int DateSeparator
, int TimeSeparator
, bool bRelative
)
602 WORD DateN
[3]{}, TimeN
[4]{};
604 // Преобразуем введённые пользователем дату и время
605 GetFileDateAndTime(CDate
,DateN
,ARRAYSIZE(DateN
),DateSeparator
);
606 GetFileDateAndTime(CTime
,TimeN
,ARRAYSIZE(TimeN
),TimeSeparator
);
610 if (DateN
[0]==(WORD
)-1||DateN
[1]==(WORD
)-1||DateN
[2]==(WORD
)-1)
612 // Пользователь оставил дату пустой, значит обнулим дату и время.
613 memset(&ft
,0,sizeof(ft
));
621 st
.wMonth
= DateN
[0];
627 st
.wMonth
= DateN
[1];
632 st
.wMonth
= DateN
[1];
639 st
.wYear
= static_cast<WORD
>(ConvertYearToFull(st
.wYear
));
644 st
.wDay
= DateN
[0]!=(WORD
)-1?DateN
[0]:0;
647 st
.wHour
= TimeN
[0]!=(WORD
)-1?(TimeN
[0]):0;
648 st
.wMinute
= TimeN
[1]!=(WORD
)-1?(TimeN
[1]):0;
649 st
.wSecond
= TimeN
[2]!=(WORD
)-1?(TimeN
[2]):0;
650 st
.wMilliseconds
= TimeN
[3]!=(WORD
)-1?(TimeN
[3]):0;
652 // преобразование в "удобоваримый" формат
656 time
.QuadPart
= st
.wMilliseconds
;
657 time
.QuadPart
+= (UINT64
)st
.wSecond
* 1000;
658 time
.QuadPart
+= (UINT64
)st
.wMinute
* 1000 * 60;
659 time
.QuadPart
+= (UINT64
)st
.wHour
* 1000 * 60 * 60;
660 time
.QuadPart
+= (UINT64
)st
.wDay
* 1000 * 60 * 60 * 24;
661 time
.QuadPart
*= 10000;
662 ft
.dwLowDateTime
= time
.LowPart
;
663 ft
.dwHighDateTime
= time
.HighPart
;
669 if (WINPORT(SystemTimeToFileTime
)(&st
,&lft
))
671 WINPORT(LocalFileTimeToFileTime
)(&lft
,&ft
);
676 void ConvertDate(const FILETIME
&ft
,FARString
&strDateText
, FARString
&strTimeText
,int TimeLength
,
677 int Brief
,int TextMonth
,int FullYear
,int DynInit
)
679 static int WDateFormat
;
680 static wchar_t WDateSeparator
,WTimeSeparator
,WDecimalSeparator
;
681 static bool Init
=false;
682 static SYSTEMTIME lt
;
684 wchar_t DateSeparator
,TimeSeparator
,DecimalSeparator
;
688 WDateFormat
=GetDateFormat();
689 WDateSeparator
=GetDateSeparator();
690 WTimeSeparator
=GetTimeSeparator();
691 WDecimalSeparator
=GetDecimalSeparator();
692 WINPORT(GetLocalTime
)(<
);
696 DateFormat
=DynInit
?GetDateFormat():WDateFormat
;
697 DateSeparator
=DynInit
?GetDateSeparator():WDateSeparator
;
698 TimeSeparator
=DynInit
?GetTimeSeparator():WTimeSeparator
;
699 DecimalSeparator
=DynInit
?GetDecimalSeparator():WDecimalSeparator
;
700 int CurDateFormat
=DateFormat
;
702 if (Brief
&& CurDateFormat
==2)
708 if (!ft
.dwHighDateTime
)
715 WINPORT(FileTimeToLocalFileTime
)(&ft
,&ct
);
716 WINPORT(FileTimeToSystemTime
)(&ct
,&st
);
717 //if ( !strTimeText.IsEmpty() )
719 const wchar_t *Letter
=L
"";
723 Letter
=(st
.wHour
<12) ? L
"a":L
"p";
733 strTimeText
.Format(L
"%02d%c%02d%ls",st
.wHour
,TimeSeparator
,st
.wMinute
,Letter
);
736 FARString strFullTime
;
737 strFullTime
.Format(L
"%02d%c%02d%c%02d%c%03d",st
.wHour
,TimeSeparator
,
738 st
.wMinute
,TimeSeparator
,st
.wSecond
,DecimalSeparator
,st
.wMilliseconds
);
739 strTimeText
.Format(L
"%.*ls",TimeLength
, strFullTime
.CPtr());
742 //if ( !strDateText.IsEmpty() )
751 const wchar_t *Month
=(Msg::MonthJan
+st
.wMonth
-1);
753 switch (CurDateFormat
)
756 strDateText
.Format(L
"%3.3ls %2d %02d",Month
,st
.wDay
,Year
);
759 strDateText
.Format(L
"%2d %3.3ls %02d",st
.wDay
,Month
,Year
);
762 strDateText
.Format(L
"%02d %3.3ls %2d",Year
,Month
,st
.wDay
);
769 int w1
=2, w2
=2, w3
=2;
770 wchar_t f1
=L
'0', f2
=L
'0', f3
=FullYear
==2?L
' ':L
'0';
771 switch (CurDateFormat
)
791 Fmt
<<fmt::FillChar(f1
)<<fmt::Expand(w1
)<<p1
<<DateSeparator
<<fmt::FillChar(f2
)<<fmt::Expand(w2
)<<p2
<<DateSeparator
<<fmt::FillChar(f3
)<<fmt::Expand(w3
)<<p3
;
792 strDateText
=std::move(Fmt
.strValue());
798 strDateText
.Truncate(TextMonth
? 6 : 5);
800 if (lt
.wYear
!=st
.wYear
)
801 strTimeText
.Format(L
"%5d",st
.wYear
);
805 void ConvertRelativeDate(const FILETIME
&ft
,FARString
&strDaysText
,FARString
&strTimeText
)
807 ULARGE_INTEGER time
={{ft
.dwLowDateTime
,ft
.dwHighDateTime
}};
809 UINT64 ms
= (time
.QuadPart
/=10000)%1000;
810 UINT64 s
= (time
.QuadPart
/=1000)%60;
811 UINT64 m
= (time
.QuadPart
/=60)%60;
812 UINT64 h
= (time
.QuadPart
/=60)%24;
813 UINT64 d
= time
.QuadPart
/=24;
815 FormatString DaysText
;
817 strDaysText
=std::move(DaysText
.strValue());
819 FormatString TimeText
;
820 TimeText
<<fmt::Expand(2)<<fmt::FillChar(L
'0')<<h
<<GetTimeSeparator()<<fmt::Expand(2)<<fmt::FillChar(L
'0')<<m
<<GetTimeSeparator()<<fmt::Expand(2)<<fmt::FillChar(L
'0')<<s
<<GetDecimalSeparator()<<fmt::Expand(3)<<fmt::FillChar(L
'0')<<ms
;
821 strTimeText
=std::move(TimeText
.strValue());