1 /******************************************************************************
2 *
3 * Copyright (C) 2004-2008, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * Author: Alexey Krivonogov ( gentee )
11 *
12 ******************************************************************************/
13
14 /*-----------------------------------------------------------------------------
15 * Id: datetime L "Date & Time"
16 *
17 * Summary: Functions for working with date and time.
18 *
19 * List: *#lng/opers#,datetime_opeq,datetime_opadd,datetime_opsub,datetime_opdif,
20 datetime_opeqeq,datetime_opless,datetime_opgr,
21 *#lng/funcs#,abbrnameofday,days,daysinmonth,firstdayofweek,
22 getdateformat,getdatetime,gettimeformat,isleapyear,nameofmonth,
23 *#lng/methods#,datetime_dayofweek,datetime_dayofyear,datetime_gettime,
24 datetime_setdate,
25 *File time functions and operators,filetime_opeq,filetime_opeqeq,
26 filetime_opless,filetime_opgr,datetimetoftime,
27 ftimetodatetime,getfiledatetime,
28 *#lng/types#,tdatetime,tfiletime
29 *
30 -----------------------------------------------------------------------------*/
31
32 /*-----------------------------------------------------------------------------
33 * Id: getdatetime F
34 *
35 * Summary: Getting date and time as strings. Get date and time in the current
36 Windows string format.
37 *
38 * Params: systime - Datetime structure.
39 date - The string for getting the date. It can be 0->str.
40 time - The string for getting time. It can be 0->str.
41 *
42 -----------------------------------------------------------------------------*/
43
44 func getdatetime( datetime systime, str date, str time )
45 {
46 if date
47 {
48 date.setlen( GetDateFormat( 0, 0, systime, 0, date->buf.data,
49 date->buf.size ) - 1 )
50 }
51 if time
52 {
53 time.setlen( GetTimeFormat( 0, 0, systime, 0, time->buf.data,
54 time->buf.size ) - 1 )
55 }
56 }
57
58 /*-----------------------------------------------------------------------------
59 * Id: getdateformat_param D
60 *
61 * Summary: Parameters for getdateformat
62 *
63 -----------------------------------------------------------------------------
64 #define dd 0 // Day as a number.
65 #define ddd 0 // Weekday as an abbriviation.
66 #define dddd 0 // The full name of a weekday.
67 #define MM 0 // Month as a number.
68 #define MMM 0 // Month as an abbreviation.
69 #define MMMM 0 // The full name of a month.
70 #define yy 0 // The last tow digits in a year.
71 #define yyyy 0 // Year.
72
73 //---------------------------------------------------------------------------*/
74
75 /*-----------------------------------------------------------------------------
76 * Id: getdateformat F
77 *
78 * Summary: Get date in the specified format.
79 *
80 * Params: systime - The variable containing date.
81 format - Date format. It can contain the following values:/
82 $$[getdateformat_param]
83 date - The string for getting the date.
84 *
85 * Return: #lng/retpar( date )
86 *
87 -----------------------------------------------------------------------------*/
88
89 func str getdateformat( datetime systime, str format, str date )
90 {
91 date.reserve( 64 )
92 return date.setlen( GetDateFormat( 0, 0, systime, format.ptr(),
93 date.ptr(), 64 ) - 1 )
94 }
95
96 /*-----------------------------------------------------------------------------
97 * Id: gettimeformat_param D
98 *
99 * Summary: Parameters for gettimeformat
100 *
101 -----------------------------------------------------------------------------
102 #define hh 0 // Hours - 12-hour format.
103 #define HH 0 // Hours -24-hour format.
104 #define mm 0 // Minutes.
105 #define ss 0 // Seconds.
106 #define tt 0 // Time marker, such as AM or PM.
107
108 //---------------------------------------------------------------------------*/
109
110 /*-----------------------------------------------------------------------------
111 * Id: gettimeformat F
112 *
113 * Summary: Get time in the specified format.
114 *
115 * Params: systime - The variable containing time.
116 format - Time format. It can contain the following values: /
117 $$[gettimeformat_param]
118 time - The string for getting time.
119 *
120 * Return: #lng/retpar( time )
121 *
122 -----------------------------------------------------------------------------*/
123
124 func str gettimeformat( datetime systime, str format, str time )
125 {
126 time.reserve( 64 )
127 return time.setlen( GetTimeFormat( 0, 0, systime, format.ptr(),
128 time.ptr(), 64 ) - 1 )
129 }
130
131 /*-----------------------------------------------------------------------------
132 * Id: datetime_opeq F4
133 *
134 * Summary: Copying datatime structure.
135 *
136 * Return: The result datetime.
137 *
138 -----------------------------------------------------------------------------*/
139
140 operator datetime =( datetime left, datetime right )
141 {
142 left.year = right.year
143 left.month = right.month
144 left.day = right.day
145 left.hour = right.hour
146 left.minute = right.minute
147 left.second = right.second
148 left.msec = right.msec
149 return left
150 }
151
152 /*-----------------------------------------------------------------------------
153 * Id: datetime_opeqeq F4
154 *
155 * Summary: Comparison operations.
156 *
157 * Return: Returns #b(1) if the datetimes are equal. Otherwise, it returns #b(0).
158 *
159 -----------------------------------------------------------------------------*/
160
161 operator uint ==( datetime left, datetime right )
162 {
163 if left.year != right.year : return 0
164 if left.month != right.month : return 0
165 if left.day != right.day : return 0
166 if left.hour != right.hour : return 0
167 if left.minute != right.minute : return 0
168 if left.second != right.second : return 0
169 if left.msec != right.msec : return 0
170 return 1
171 }
172
173 /*-----------------------------------------------------------------------------
174 * Id: datetime_opeqeq_1 FC
175 *
176 * Summary: Comparison operation.
177 *
178 * Return: Returns #b(0) if the datetimes are equal. Otherwise, it returns #b(1).
179 *
180 * Define: operator uint !=( datetime left, datetime right )
181 *
182 -----------------------------------------------------------------------------*/
183
184 /*-----------------------------------------------------------------------------
185 * Id: datetime_opless F4
186 *
187 * Summary: Comparison operation.
188 *
189 * Title: datetime < datetime
190 *
191 * Return: Returns #b(1) if the first datetime is less than the second one.
192 Otherwise, it returns #b(0).
193 *
194 -----------------------------------------------------------------------------*/
195
196 operator uint <( datetime left, datetime right )
197 {
198 if left.year < right.year : return 1
199 if left.year > right.year : return 0
200 if left.month < right.month : return 1
201 if left.month > right.month : return 0
202 if left.day < right.day : return 1
203 if left.day > right.day : return 0
204 if left.hour < right.hour : return 1
205 if left.hour > right.hour : return 0
206 if left.minute < right.minute : return 1
207 if left.minute > right.minute : return 0
208 if left.second < right.second : return 1
209 if left.second > right.second : return 0
210 if left.msec < right.msec : return 1
211 return 0
212 }
213
214 /*-----------------------------------------------------------------------------
215 * Id: datetime_opless_1 FC
216 *
217 * Summary: Comparison operation.
218 *
219 * Title: datetime <= datetime
220 *
221 * Return: Returns #b(1) if the first datetime is less or equal the second one.
222 Otherwise, it returns #b(0).
223 *
224 * Define: operator uint <=( datetime left, datetime right )
225 *
226 -----------------------------------------------------------------------------*/
227
228 /*-----------------------------------------------------------------------------
229 * Id: datetime_opgr F4
230 *
231 * Summary: Comparison operation.
232 *
233 * Title: datetime > datetime
234 *
235 * Return: Returns #b(1) if the first datetime is greater than the second one.
236 Otherwise, it returns #b(0).
237 *
238 -----------------------------------------------------------------------------*/
239
240 operator uint >( datetime left, datetime right )
241 {
242 if left.year > right.year : return 1
243 if left.year < right.year : return 0
244 if left.month > right.month : return 1
245 if left.month < right.month : return 0
246 if left.day > right.day : return 1
247 if left.day < right.day : return 0
248 if left.hour > right.hour : return 1
249 if left.hour < right.hour : return 0
250 if left.minute > right.minute : return 1
251 if left.minute < right.minute : return 0
252 if left.second > right.second : return 1
253 if left.second < right.second : return 0
254 if left.msec > right.msec : return 1
255 return 0
256 }
257
258 /*-----------------------------------------------------------------------------
259 * Id: datetime_opgr_1 FC
260 *
261 * Summary: Comparison operation.
262 *
263 * Title: datetime >= datetime
264 *
265 * Return: Returns #b(1) if the first datetime is greater or equal the second
266 one. Otherwise, it returns #b(0).
267 *
268 * Define: operator uint >=( datetime left, datetime right )
269 *
270 -----------------------------------------------------------------------------*/
271
272 /*-----------------------------------------------------------------------------
273 * Id: isleapyear F
274 *
275 * Summary: Leap year check.
276 *
277 * Params: year - The year being checked.
278 *
279 * Return: Returns 1 if the year is a leap one and 0 otherwise.
280 *
281 -----------------------------------------------------------------------------*/
282
283 func uint isleapyear( ushort year )
284 {
285 return ?( !( year % 4 ) && ( ( year % 100 ) || !( year % 400 )), 1, 0 )
286 }
287
288 /*-----------------------------------------------------------------------------
289 * Id: daysinmonth F
290 *
291 * Summary: The number of days in a month. Leap years are taken into account
292 for February.
293 *
294 * Params: year - Year.
295 month - Month.
296 *
297 * Return: Returns the number of days in the month.
298 *
299 -----------------------------------------------------------------------------*/
300
301 func uint daysinmonth( ushort year, ushort month )
302 {
303 buf months
304
305 if !month : month = 1
306 if month > 12 : month = 12
307
308 months = '\i 31, \( byte( ?( isleapyear( year ), 29, 28))), 31, 30, 31,
309 30, 31, 31, 30, 31, 30, 31'
310 return uint( months[ month - 1 ] )
311 }
312
313 /*-----------------------------------------------------------------------------
314 * Id: datetime_dayofyear F3
315 *
316 * Summary: Get the number of a particular day in the year.
317 *
318 * Return: Returns the number of a particular day in the year.
319 *
320 -----------------------------------------------------------------------------*/
321
322 method uint datetime.dayofyear
323 {
324 uint i result
325
326 fornum i = 1, this.month
327 {
328 result += daysinmonth( this.year, i )
329 }
330 return result + this.day
331 }
332
333 /*-----------------------------------------------------------------------------
334 * Id: days F
335 *
336 * Summary: The number of days between two dates.
337 *
338 * Params: left - The first date for comparison.
339 right - The second date for comparison.
340 *
341 * Return: Returns the number of days between two dates. If the first date is
342 greater than the second one, the return value will be negative.
343 *
344 -----------------------------------------------------------------------------*/
345
346 func int days( datetime left, datetime right )
347 {
348 uint less great
349 int result
350 uint i
351
352 less as left
353 great as right
354
355 if left > right
356 {
357 less as right
358 great as left
359 }
360
361 for i = less.year, i < great.year, i++
362 {
363 result += ?( isleapyear( i ), 366, 365 )
364 }
365 result -= less.dayofyear()
366 result += great.dayofyear()
367
368 return ?( left > right, -result, result )
369 }
370
371 /*-----------------------------------------------------------------------------
372 * Id: datetime_gettime F3
373 *
374 * Summary: Getting the current date and time. The weekday is set automatically.
375 *
376 * Return: #lng/retobj#
377 *
378 -----------------------------------------------------------------------------*/
379
380 method datetime datetime.gettime()
381 {
382 GetLocalTime( this )
383 return this
384 }
385
386 /*-----------------------------------------------------------------------------
387 * Id: datetime_dayofweek F3
388 *
389 * Summary: Get the weekday.
390 *
391 * Return: Returns the weekday. 0 is Sunday, 1 is Monday...
392 *
393 -----------------------------------------------------------------------------*/
394
395 method uint datetime.dayofweek
396 {
397 datetime curtime
398 int dif
399
400 GetLocalTime( curtime )
401 dif = days( this, curtime )
402 this.dayofweek = ( 7 + curtime.dayofweek - ( dif % 7 )) % 7
403 return uint( this.dayofweek )
404 }
405
406 /*-----------------------------------------------------------------------------
407 * Id: datetime_opadd F4
408 *
409 * Summary: Adding days to a date.
410 *
411 * Return: The result datetime.
412 *
413 -----------------------------------------------------------------------------*/
414
415 operator datetime +=( datetime left, uint next )
416 {
417 uint dif i
418 uint curday = left.dayofyear()
419
420 while ( dif = ?( isleapyear( left.year ), 366, 365 ) - curday ) < next
421 {
422 left.year++
423 next -= dif + 1
424 left.month = 1
425 left.day = 1
426 curday = 1
427 }
428 while ( dif = daysinmonth( left.year, left.month ) - left.day ) < next
429 {
430 left.month++
431 next -= dif + 1
432 left.day = 1
433 }
434 left.day += next
435
436 return left
437 }
438
439 /*-----------------------------------------------------------------------------
440 * Id: datetime_opsub F4
441 *
442 * Summary: Subtracting days from a date.
443 *
444 * Return: The result datetime.
445 *
446 -----------------------------------------------------------------------------*/
447
448 operator datetime -=( datetime left, uint next )
449 {
450 uint dif i
451 uint curday = left.dayofyear()
452
453 while curday <= next
454 {
455 left.year--
456 next -= curday
457 left.month = 12
458 left.day = 31
459 curday = ?( isleapyear( left.year ), 366, 365 )
460 }
461 while left.day <= next
462 {
463 left.month--
464 next -= left.day
465 left.day = daysinmonth( left.year, left.month )
466 }
467 left.day -= next
468
469 return left
470 }
471
472 /*-----------------------------------------------------------------------------
473 * Id: datetime_setdate F2
474 *
475 * Summary: Specifying a date. The weekday is set automatically.
476 *
477 * Params: day - Day.
478 month - Month.
479 year - Year.
480 *
481 * Return: #lng/retobj#
482 *
483 -----------------------------------------------------------------------------*/
484
485 method datetime datetime.setdate( uint day, uint month, uint year )
486 {
487 if !year : year = 1
488 if year > 0xFFFF : year = 0xFFFF
489 this.year = year
490 if !month : month = 1
491 if month > 12 : month = 12
492 this.month = month
493 if !day : day = 1
494 if day > daysinmonth( year, month ) : day = daysinmonth( year, month )
495 this.day = day
496 this.dayofweek()
497
498 return this
499 }
500
501 func uint makelangid( uint primary, uint sublang )
502 {
503 return ( sublang << 10 ) | primary
504 }
505
506 func uint makelcid( uint langid, uint sortid )
507 {
508 return ( sortid << 16 ) | langid
509 }
510
511 func uint localeuser()
512 {
513 uint langid = makelangid( $LANG_NEUTRAL, $SUBLANG_DEFAULT )
514 return makelcid( langid, $SORT_DEFAULT)
515 }
516
517 func uint localesystem()
518 {
519 uint langid = makelangid( $LANG_NEUTRAL, $SUBLANG_SYS_DEFAULT )
520 return makelcid( langid, $SORT_DEFAULT )
521 }
522
523 /*-----------------------------------------------------------------------------
524 * Id: nameofmonth F
525 *
526 * Summary: Get the name of a month in the user's language.
527 *
528 * Params: ret - Result string.
529 month - The number of the month from 1.
530 *
531 * Return: #lng/retpar( ret )
532 *
533 -----------------------------------------------------------------------------*/
534
535 func str nameofmonth( str ret, uint month )
536 {
537 if month > 12 : month = 12
538 if !month : month = 1
539 ret.reserve( 32 )
540 GetLocaleInfo( localeuser(),
541 $LOCALE_SMONTHNAME1 + month - 1,
542 ret.ptr(), 32 )
543
544 ret.setlenptr()
545 return ret
546 }
547
548 /*-----------------------------------------------------------------------------
549 * Id: firstdayofweek F1
550 *
551 * Summary: Get the first day of a week for the user's locale.
552 *
553 * Return: Returns the number of the weekday. 0 is Sunday, 1 is Monday...
554 *
555 -----------------------------------------------------------------------------*/
556
557 func uint firstdayofweek()
558 {
559 str ret
560
561 ret.reserve( 8 )
562 GetLocaleInfo( localeuser(),
563 $LOCALE_IFIRSTDAYOFWEEK,
564 ret.ptr(), 8 )
565 ret.setlenptr()
566 return ( uint( ret ) + 1 ) % 7
567
568 }
569
570 /*-----------------------------------------------------------------------------
571 * Id: abbrnameofday F
572 *
573 * Summary: Get the short name of a weekday in the user's language.
574 *
575 * Params: ret - The string for getting the result.
576 dayofweek - The number of the weekday. 0 is Sunday, 1 is Monday...
577 *
578 * Return: #lng/retpar( ret )
579 *
580 -----------------------------------------------------------------------------*/
581
582 func str abbrnameofday( str ret, uint dayofweek )
583 {
584 ret.reserve( 24 )
585
586 dayofweek %= 7
587 if !dayofweek : dayofweek = 7
588
589 GetLocaleInfo( localeuser(),
590 $LOCALE_SABBREVDAYNAME1 + dayofweek - 1,
591 ret.ptr(), 24 )
592 ret.setlenptr()
593 return ret
594 }
595
596 /*-----------------------------------------------------------------------------
597 * Id: filetime_opeq F4
598 *
599 * Summary: Copying filetime structure.
600 *
601 * Return: The result filetime.
602 *
603 -----------------------------------------------------------------------------*/
604
605 operator filetime =( filetime left, filetime right )
606 {
607 left.lowdtime = right.lowdtime
608 left.highdtime = right.highdtime
609
610 return left
611 }
612
613
614 /*-----------------------------------------------------------------------------
615 * Id: filetime_opeqeq F4
616 *
617 * Summary: Comparison operations.
618 *
619 * Return: Returns #b(1) if the filetimes are equal. Otherwise, it returns #b(0).
620 *
621 -----------------------------------------------------------------------------*/
622
623 operator uint ==( filetime left, filetime right )
624 {
625 return !CompareFileTime( left, right )
626 }
627
628 /*-----------------------------------------------------------------------------
629 * Id: filetime_opeqeq_1 FC
630 *
631 * Summary: Comparison operation.
632 *
633 * Return: Returns #b(0) if the filetimes are equal. Otherwise, it returns #b(1).
634 *
635 * Define: operator uint !=( filetime left, filetime right )
636 *
637 -----------------------------------------------------------------------------*/
638
639 /*-----------------------------------------------------------------------------
640 * Id: filetime_opless F4
641 *
642 * Summary: Comparison operation.
643 *
644 * Title: filetime < filetime
645 *
646 * Return: Returns #b(1) if the first filetime is less than the second one.
647 Otherwise, it returns #b(0).
648 *
649 -----------------------------------------------------------------------------*/
650
651 operator uint <( filetime left, filetime right )
652 {
653 return CompareFileTime( left, right ) < 0
654 }
655
656 /*-----------------------------------------------------------------------------
657 * Id: filetime_opless_1 FC
658 *
659 * Summary: Comparison operation.
660 *
661 * Title: filetime <= filetime
662 *
663 * Return: Returns #b(1) if the first filetime is less or equal the second one.
664 Otherwise, it returns #b(0).
665 *
666 * Define: operator uint <=( filetime left, filetime right )
667 *
668 -----------------------------------------------------------------------------*/
669
670 /*-----------------------------------------------------------------------------
671 * Id: filetime_opgr F4
672 *
673 * Summary: Comparison operation.
674 *
675 * Title: filetime > filetime
676 *
677 * Return: Returns #b(1) if the first filetime is greater than the second one.
678 Otherwise, it returns #b(0).
679 *
680 -----------------------------------------------------------------------------*/
681
682 operator uint >( filetime left, filetime right )
683 {
684 return CompareFileTime( left, right ) > 0
685 }
686
687 /*-----------------------------------------------------------------------------
688 * Id: filetime_opgr_1 FC
689 *
690 * Summary: Comparison operation.
691 *
692 * Title: filetime >= filetime
693 *
694 * Return: Returns #b(1) if the first filetime is greater or equal the second
695 one. Otherwise, it returns #b(0).
696 *
697 * Define: operator uint >=( filetime left, filetime right )
698 *
699 -----------------------------------------------------------------------------*/
700
701 /*-----------------------------------------------------------------------------
702 * Id: ftimetodatetime F
703 *
704 * Summary: Converting date from filetime into datetime.
705 *
706 * Params: ft - A structure of the filetime type. Can be taken from the finfo /
707 structure.
708 dt - A datetime structure for getting the result.
709 local - Specify 1 if you need to take the local time into account.
710 *
711 * Return: #lng/retpar( dt )
712 *
713 -----------------------------------------------------------------------------*/
714
715 func datetime ftimetodatetime( filetime ft, datetime dt, uint local )
716 {
717 filetime ftime = ft
718
719 if local : FileTimeToLocalFileTime( ft, ftime )
720 FileTimeToSystemTime( ftime, dt )
721 return dt
722 }
723
724 /*-----------------------------------------------------------------------------
725 * Id: getfiledatetime F
726 *
727 * Summary: Getting date and time as strings. Get the data and time of the last
728 file modification as strings.
729 *
730 * Params: ftime - A structure of the filetime type. Can be taken from /
731 the finfo structure.
732 date - The string for writing date. It can be 0->str.
733 time - The string for writing time. It can be 0->str.
734 *
735 -----------------------------------------------------------------------------*/
736
737 func getfiledatetime( filetime ftime, str date, str time )
738 {
739 datetime st
740
741 ftimetodatetime( ftime, st, 1 )
742 getdatetime( st, date, time )
743 }
744
745 /*-----------------------------------------------------------------------------
746 * Id: datetimetoftime F
747 *
748 * Summary: Converting date from datetime into filetime.
749 *
750 * Params: dt - Datetime structure.
751 ft - The variable of the filetime type for getting the result.
752 *
753 * Return: #lng/retf#
754 *
755 -----------------------------------------------------------------------------*/
756
757 func uint datetimetoftime( datetime dt, filetime ft )
758 {
759 return SystemTimeToFileTime( dt, ft )
760 }
761
762 /*-----------------------------------------------------------------------------
763 * Id: datetime_opdif F4
764 *
765 * Summary: Difference between two dates as days and time. All values are
766 positive numbers.
767 *
768 * Return: The result datetime.
769 *
770 -----------------------------------------------------------------------------*/
771
772 operator datetime -<result>( datetime left, datetime right )
773 {
774 uint dt shift, xshift
775
776 dt as left
777 result = right
778
779 if left > right
780 {
781 result = left
782 dt as right
783 }
784 result.year = 0
785 result.month = 0
786 result.day = abs( days( left, right ))
787 if result.msec < dt.msec
788 {
789 shift = 1
790 result.msec += 1000
791 }
792 result.msec -= dt.msec
793 if result.second < dt.second + shift
794 {
795 xshift = 1
796 result.second += 60
797 }
798 result.second -= dt.second + shift
799 shift = 0
800
801 if result.minute < dt.minute + xshift
802 {
803 shift = 1
804 result.minute += 60
805 }
806 result.minute -= dt.minute + xshift
807 xshift = 0
808 if result.hour < dt.hour + shift
809 {
810 xshift = 1
811 result.hour += 24
812 }
813 result.hour -= dt.hour + shift
814 result.day -= xshift
815
816 return //result
817 }
818
819 /*-----------------------------------------------------------------------------
820 ** Id: datetime_opdif_1 FC
821 *
822 * Summary: Difference between two dates as days and time. All values are
823 positive numbers.
824 *
825 * Return: The result datetime.
826 *
827 -----------------------------------------------------------------------------*/
828
829 operator datetime -=( datetime left, datetime right )
830 {
831 return left = left - right
832 }
833
834
835