support full-width/composite characters and true color palette in terminal (#1386)
[far2l.git] / far2l / src / datetime.cpp
blob93fd125d529bc2d8c28b939bd46a70d53b9b86ae
1 /*
2 datetime.cpp
4 Функции для работы с датой и временем
5 */
6 /*
7 Copyright (c) 1996 Eugene Roshal
8 Copyright (c) 2000 Far Group
9 All rights reserved.
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions
13 are met:
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"
38 #include "lang.hpp"
39 #include "language.hpp"
40 #include "config.hpp"
41 #include "strmix.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;
59 int GetDateFormat()
61 int Result = 1;
62 // GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_IDATE|LOCALE_RETURN_NUMBER,reinterpret_cast<LPWSTR>(&Result),sizeof(Result)/sizeof(WCHAR));
63 return Result;
66 wchar_t GetDateSeparator()
68 // wchar_t Info[100];
69 // GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SDATE,Info,ARRAYSIZE(Info));
70 // return *Info;
71 return L'/';
74 wchar_t GetTimeSeparator()
76 // wchar_t Info[100];
77 // GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STIME,Info,ARRAYSIZE(Info));
78 // return *Info;
79 return L':';
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();
143 CurLang=0;
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(),
152 tmPtr->tm_mday,
153 tmPtr->tm_hour,
154 tmPtr->tm_min,
155 tmPtr->tm_sec,
156 tmPtr->tm_year+1900);
159 static void st_time(FARString &strDest,const tm *tmPtr,const wchar_t chr)
161 int DateSeparator=GetDateSeparator();
163 if (chr==L'v')
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);
166 strDest.Upper(3,3);
168 else switch (GetDateFormat())
170 case 0:
171 strDest.Format(L"%02d%lc%02d%lc%4d",
172 tmPtr->tm_mon+1,
173 DateSeparator,
174 tmPtr->tm_mday,
175 DateSeparator,
176 tmPtr->tm_year+1900);
177 break;
178 case 1:
179 strDest.Format(L"%02d%lc%02d%lc%4d",
180 tmPtr->tm_mday,
181 DateSeparator,
182 tmPtr->tm_mon+1,
183 DateSeparator,
184 tmPtr->tm_year+1900);
185 break;
186 default:
187 strDest.Format(L"%4d%lc%02d%lc%02d",
188 tmPtr->tm_year+1900,
189 DateSeparator,
190 tmPtr->tm_mon+1,
191 DateSeparator,
192 tmPtr->tm_mday);
193 break;
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;
202 if (firstweekday==1)
204 if (!wday) // sunday
205 wday=6;
206 else
207 wday--;
210 int ret=((timeptr->tm_yday+7-wday)/7);
212 if (ret<0)
213 ret=0;
215 return ret;
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)
227 * From 1003.2:
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?
245 * We know that
246 * (timeptr->tm_yday - jan1.tm_yday) MOD 7 ==
247 * (timeptr->tm_wday - jan1.tm_wday) MOD 7
248 * and that
249 * jan1.tm_yday == 0
250 * and that
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);
256 if (jan1day<0)
257 jan1day+=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
266 * never be 0.
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.
272 switch (jan1day)
274 case 1: // Monday
275 break;
276 case 2: // Tuesday
277 case 3: // Wednesday
278 case 4: // Thursday
279 weeknum++;
280 break;
281 case 5: // Friday
282 case 6: // Saturday
283 case 0: // Sunday
285 if (!weeknum)
287 #ifdef USE_BROKEN_XPG4
288 /* XPG4 (as of March 1994) says 53 unconditionally */
289 weeknum = 53;
290 #else
291 // get week number of last week of last year
292 // 12/31 last year
293 tm dec31ly=*timeptr;
294 dec31ly.tm_year--;
295 dec31ly.tm_mon=11;
296 dec31ly.tm_mday=31;
297 dec31ly.tm_wday=!jan1day?6:jan1day-1;
298 dec31ly.tm_yday=364+isleap(dec31ly.tm_year+1900);
299 weeknum=iso8601wknum(&dec31ly);
300 #endif
303 break;
306 if (timeptr->tm_mon==11)
309 * The last week of the year
310 * can be in week 1 of next year.
311 * Sigh.
313 * This can only happen if
314 * M T W
315 * 29 30 31
316 * 30 31
317 * 31
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))
322 weeknum=1;
325 return weeknum;
328 size_t WINAPI StrFTime(FARString &strDest, const wchar_t *Format,const tm *t)
330 if (CurLang==-1 && Lang.IsLanguageLoaded())
331 PrepareStrFTime();
333 // меняем язык.
334 CurLang=0;
335 size_t Len;
337 for (Len=1; *Format; Format++)
339 if (*Format!=L'%')
341 Len++;
342 const wchar_t Text[]={*Format,0};
343 strDest+=Text;
345 #if 1
346 else
348 FARString strBuf;
350 switch (*++Format)
352 case L'L':
353 CurLang=!CurLang;
354 continue;
355 // Краткое имя дня недели (Sun,Mon,Tue,Wed,Thu,Fri,Sat)
356 // abbreviated weekday name
357 case L'a':
358 strBuf=AWeekday[CurLang][!WeekFirst?((t->tm_wday+6)%7):(!t->tm_wday?6:t->tm_wday-1)];
359 break;
360 // Полное имя дня недели
361 // full weekday name
362 case L'A':
363 strBuf=Weekday[CurLang][!WeekFirst?((t->tm_wday+6)%7):(!t->tm_wday?6:t->tm_wday-1)];
364 break;
365 // Краткое имя месяца (Jan,Feb,...)
366 // abbreviated month name
367 case L'h':
368 case L'b':
369 strBuf=AMonth[CurLang][t->tm_mon];
370 break;
371 // Полное имя месяца
372 // full month name
373 case L'B':
374 strBuf=Month[CurLang][t->tm_mon];
375 break;
376 //Дата и время в формате WDay Mnt Day HH:MM:SS yyyy
377 //appropriate date and time representation
378 case L'c':
379 atime(strBuf,t);
380 break;
381 // Столетие как десятичное число (00 - 99). Например, 1992 => 19
382 case L'C':
383 strBuf.Format(L"%02d",(t->tm_year+1900)/100);
384 break;
385 // day of month, blank padded
386 case L'e':
387 // Две цифры дня месяца (01 - 31)
388 // day of the month, 01 - 31
389 case L'd':
390 strBuf.Format(*Format==L'e'?L"%2d":L"%02d",t->tm_mday);
391 break;
392 // hour, 24-hour clock, blank pad
393 case L'k':
394 // Две цифры часа (00 - 23)
395 // hour, 24-hour clock, 00 - 23
396 case L'H':
397 strBuf.Format(*Format==L'k'?L"%2d":L"%02d",t->tm_hour);
398 break;
399 // hour, 12-hour clock, 1 - 12, blank pad
400 case L'l':
401 // Две цифры часа (01 - 12)
402 // hour, 12-hour clock, 01 - 12
403 case L'I':
405 int I=t->tm_hour%12;
407 if (!I)
408 I=12;
410 strBuf.Format(*Format==L'l'?L"%2d":L"%02d",I);
411 break;
413 // Три цифры дня в году (001 - 366)
414 // day of the year, 001 - 366
415 case L'j':
416 strBuf.Format(L"%03d",t->tm_yday+1);
417 break;
418 // Две цифры месяца, как десятичное число (1 - 12)
419 // month, 01 - 12
420 case L'm':
422 // %mh - Hex month digit
423 // %m0 - ведущий 0
424 const wchar_t *fmt=Format[1]==L'h'?L"%X":Format[1]==L'0'?L"%02d":L"%d";
426 if (fmt[1]!=L'd')
427 Format++;
429 strBuf.Format(fmt,t->tm_mon+1);
430 break;
432 // Две цифры минут (00 - 59)
433 // minute, 00 - 59
434 case L'M':
435 strBuf.Format(L"%02d",t->tm_min);
436 break;
437 // AM или PM
438 // am or pm based on 12-hour clock
439 case L'p':
440 strBuf=(t->tm_hour/12)?L"PM":L"AM";
441 break;
442 // Две цифры секунд (00 - 59)
443 // second, 00 - 59
444 case L'S':
445 strBuf.Format(L"%02d",t->tm_sec);
446 break;
447 // День недели где 0 - Воскресенье (Sunday) (0 - 6)
448 // weekday, Sunday == 0, 0 - 6
449 case L'w':
450 strBuf.Format(L"%d",t->tm_wday);
451 break;
452 // Две цифры номера недели, где Воскресенье (Sunday)
453 // является первым днем недели (00 - 53)
454 // week of year, Sunday is first day of week
455 case L'U':
456 // Две цифры номера недели, где Понедельник (Monday)
457 // является первым днем недели (00 - 53)
458 // week of year, Monday is first day of week
459 case L'W':
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);
464 if (I<0)
465 I+=7;
467 strBuf.Format(L"%02d",(t->tm_yday+I-(*Format==L'W'))/7);
468 break;
470 // date as dd-bbb-YYYY
471 case L'v':
472 // Дата в формате mm.dd.yyyy
473 // appropriate date representation
474 case L'D':
475 case L'x':
476 st_time(strBuf,t,*Format);
477 break;
478 // Время в формате HH:MM:SS
479 // appropriate time representation
480 case L'T':
481 case L'X':
483 int TimeSeparator=GetTimeSeparator();
484 strBuf.Format(L"%02d%c%02d%c%02d",t->tm_hour,TimeSeparator,t->tm_min,TimeSeparator,t->tm_sec);
485 break;
487 // Две цифры года без столетия (00 to 99)
488 // year without a century, 00 - 99
489 case L'y':
490 strBuf.Format(L"%02d",t->tm_year%100);
491 break;
492 // Год со столетием (19yy-20yy)
493 // year with century
494 case L'Y':
495 strBuf.Format(L"%d",1900+t->tm_year);
496 break;
497 // Имя часового пояса или пусто, если часовой пояс не задан
498 case L'Z':
499 //todo strBuf.Format(L"%+03d%02d",-(_timezone/3600),-(_timezone/60)%60);
500 //Ptr = _tzname[ t->tm_isdst ];
501 break;
502 // same as \n
503 case L'n':
504 strBuf=L"\n";
505 break;
506 // same as \t
507 case L't':
508 strBuf=L"\t";
509 break;
510 case L'%':
511 strBuf=L"%";
512 break;
513 // time as %I:%M:%S %p
514 case L'r':
515 StrFTime(strBuf,L"%I:%M:%S %p",t);
516 break;
517 // time as %H:%M
518 case L'R':
519 StrFTime(strBuf,L"%H:%M",t);
520 break;
521 // week of year according ISO 8601
522 case L'V':
523 strBuf.Format(L"%02d",iso8601wknum(t));
524 break;
527 strDest+=strBuf;
528 Len+=strBuf.GetLength();
530 #endif
533 if (*Format)
534 return 0;
536 return Len-1;
539 size_t MkStrFTime(FARString &strDest, const wchar_t *Fmt)
541 tm *time_now;
542 time_t secs_now;
543 //todo _tzset();
544 time(&secs_now);
545 time_now=localtime(&secs_now);
547 if (!Fmt||!*Fmt)
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}};
562 return A.QuadPart;
565 void GetFileDateAndTime(const wchar_t *Src,LPWORD Dst,size_t Count,int Separator)
567 for (size_t i=0; i<Count; i++)
569 Dst[i]=(WORD)-1;
572 FARString strDigit;
573 const wchar_t *Ptr=Src;
575 for (size_t i=0; i<Count; i++)
577 Ptr=GetCommaWord(Ptr,strDigit,Separator);
579 if (Ptr)
581 const wchar_t *PtrDigit=strDigit;
583 while (*PtrDigit&&!isdigit(*PtrDigit))//todo iswdigit
585 PtrDigit++;
588 if (*PtrDigit)
590 Dst[i]=static_cast<WORD>(_wtoi(PtrDigit));
593 else
595 break;
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]{};
603 SYSTEMTIME st{};
604 // Преобразуем введённые пользователем дату и время
605 GetFileDateAndTime(CDate,DateN,ARRAYSIZE(DateN),DateSeparator);
606 GetFileDateAndTime(CTime,TimeN,ARRAYSIZE(TimeN),TimeSeparator);
608 if (!bRelative)
610 if (DateN[0]==(WORD)-1||DateN[1]==(WORD)-1||DateN[2]==(WORD)-1)
612 // Пользователь оставил дату пустой, значит обнулим дату и время.
613 memset(&ft,0,sizeof(ft));
614 return;
617 // "Оформим"
618 switch (DateFormat)
620 case 0:
621 st.wMonth = DateN[0];
622 st.wDay = DateN[1];
623 st.wYear = DateN[2];
624 break;
625 case 1:
626 st.wDay = DateN[0];
627 st.wMonth = DateN[1];
628 st.wYear = DateN[2];
629 break;
630 default:
631 st.wYear = DateN[0];
632 st.wMonth = DateN[1];
633 st.wDay = DateN[2];
634 break;
637 if (st.wYear<100)
639 st.wYear = static_cast<WORD>(ConvertYearToFull(st.wYear));
642 else
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 // преобразование в "удобоваримый" формат
653 if (bRelative)
655 ULARGE_INTEGER time;
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;
665 else
667 FILETIME lft{};
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;
683 int DateFormat;
684 wchar_t DateSeparator,TimeSeparator,DecimalSeparator;
686 if (!Init)
688 WDateFormat=GetDateFormat();
689 WDateSeparator=GetDateSeparator();
690 WTimeSeparator=GetTimeSeparator();
691 WDecimalSeparator=GetDecimalSeparator();
692 WINPORT(GetLocalTime)(&lt);
693 Init=true;
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)
703 CurDateFormat=0;
705 SYSTEMTIME st;
706 FILETIME ct;
708 if (!ft.dwHighDateTime)
710 strDateText.Clear();
711 strTimeText.Clear();
712 return;
715 WINPORT(FileTimeToLocalFileTime)(&ft,&ct);
716 WINPORT(FileTimeToSystemTime)(&ct,&st);
717 //if ( !strTimeText.IsEmpty() )
719 const wchar_t *Letter=L"";
721 if (TimeLength==6)
723 Letter=(st.wHour<12) ? L"a":L"p";
725 if (st.wHour>12)
726 st.wHour-=12;
728 if (!st.wHour)
729 st.wHour=12;
732 if (TimeLength<7)
733 strTimeText.Format(L"%02d%c%02d%ls",st.wHour,TimeSeparator,st.wMinute,Letter);
734 else
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() )
744 int Year=st.wYear;
746 if (!FullYear)
747 Year%=100;
749 if (TextMonth)
751 const wchar_t *Month=(Msg::MonthJan+st.wMonth-1);
753 switch (CurDateFormat)
755 case 0:
756 strDateText.Format(L"%3.3ls %2d %02d",Month,st.wDay,Year);
757 break;
758 case 1:
759 strDateText.Format(L"%2d %3.3ls %02d",st.wDay,Month,Year);
760 break;
761 default:
762 strDateText.Format(L"%02d %3.3ls %2d",Year,Month,st.wDay);
763 break;
766 else
768 int p1,p2,p3=Year;
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)
773 case 0:
774 p1=st.wMonth;
775 p2=st.wDay;
776 break;
777 case 1:
778 p1=st.wDay;
779 p2=st.wMonth;
780 break;
781 default:
782 p1=Year;
783 w1=FullYear==2?5:2;
784 f3=f1;
785 f1=L' ';
786 p2=st.wMonth;
787 p3=st.wDay;
788 break;
790 FormatString Fmt;
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());
796 if (Brief)
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;
816 DaysText<<d;
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());