revert between 56095 -> 55830 in arch
[AROS.git] / workbench / libs / locale / formatdate.c
blob58e125c01199b6aaf96f63fe91ab793e4cacad3c
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: English
7 */
9 #include "locale_intern.h"
10 #include <exec/types.h>
11 #include <utility/hooks.h>
12 #include <utility/date.h>
13 #include <proto/utility.h>
14 #include <clib/alib_protos.h>
16 #include <stdio.h>
18 VOID PrintDigits(UWORD number, char fill, UWORD len, const struct Hook *hook,
19 const struct Locale *locale);
20 VOID _WriteChar(char token, const struct Hook *hook,
21 const struct Locale *locale);
22 VOID _WriteString(CONST_STRPTR string, const struct Hook *hook,
23 const struct Locale *locale);
25 static const ULONG dayspermonth[13] =
26 {0 /* not used */,0,31,59,90,120,151,181,212,243,273,304,334};
28 /*****************************************************************************
30 NAME */
31 #include <proto/locale.h>
33 AROS_LH4(VOID, FormatDate,
35 /* SYNOPSIS */
36 AROS_LHA(const struct Locale *, locale, A0),
37 AROS_LHA(CONST_STRPTR, formatString, A1),
38 AROS_LHA(const struct DateStamp *, date, A2),
39 AROS_LHA(const struct Hook *, hook, A3),
41 /* LOCATION */
42 struct LocaleBase *, LocaleBase, 10, Locale)
44 /* FUNCTION
46 Generate a date string based on a template. The bytes generated are sent
47 to a user specified callback function.
49 INPUTS
51 locale -- the locale to use when formatting the string or NULL
52 for the system default locale.
53 formatString -- the formatting template string; this is much like the
54 printf() formatting style, i.e. a % followed by a
55 formatting command. The following commands exist:
57 %a -- abbreviated weekday name
58 %A -- weekday name
59 %b -- abbreviated month name
60 %B -- month name
61 %c -- the same as "%a %b %d %H:%M:%S %Y"
62 %C -- the same as "%a %b %e %T %Z %Y"
63 %d -- day number with leading zeros
64 %D -- the same as "%m/%d/%y"
65 %e -- day number with leading spaces
66 %h -- abbreviated month name
67 %H -- hour using 24 hour style with leading zeros
68 %I -- hour using 12 hour style with leading zeros
69 %j -- julian date
70 %m -- month number with leading zeros
71 %M -- the number of minutes with leading zeros
72 %n -- linefeed
73 %p -- AM or PM string
74 %q -- hour using 24 hour style
75 %Q -- hour using 12 hour style
76 %r -- the same as "%I:%M:%S %p"
77 %R -- the same as "%H:%M"
78 %S -- the number of seconds with leading zeros
79 %t -- tab
80 %T -- the same as "%H:%M:%S"
81 %U -- the week number, taking Sunday as the first day
82 of the week
83 %w -- the weekday number
84 %W -- the week number, taking Monday as the first day
85 of the week
86 %x -- the same as "%m/%d/%y"
87 %X -- the same as "%H:%M:%S"
88 %y -- the year using two digits with leading zeros
89 %Y -- the year using four digits with leading zeros
91 If the template parameter is NULL, a single null byte
92 is sent to the callback function.
94 date -- the current date
95 hook -- callback function; this is called for every character
96 generated with the following arguments:
98 * pointer to hook structure
99 * character
100 * pointer to locale
102 RESULT
104 NOTES
106 EXAMPLE
108 BUGS
110 SEE ALSO
112 ParseDate(), <libraries/locale.h>
114 INTERNALS
116 *****************************************************************************/
118 AROS_LIBFUNC_INIT
120 struct ClockData cData;
121 ULONG week, days, tmp;
122 struct Locale *def_locale = NULL;
124 if (hook == NULL)
125 return;
127 if (locale == NULL)
129 locale = OpenLocale(NULL);
130 if (locale == NULL)
131 return;
132 def_locale = (struct Locale *)locale;
135 if (formatString == NULL)
137 _WriteChar(0, hook, locale);
138 CloseLocale(def_locale);
139 return;
142 /* TODO: Amiga2Date will fail around year 2114, because then the
143 * number of seconds since 1978 won't fit in a 32 bit variable anymore!
146 Amiga2Date(date->ds_Days * 86400 + date->ds_Minute * 60 +
147 date->ds_Tick / 50, &cData);
149 while (*formatString != 0)
151 if (*formatString == '%')
153 switch (*(++formatString))
155 case 'a':
156 _WriteString(GetLocaleStr(locale, ABDAY_1 + cData.wday),
157 hook, locale);
158 break;
160 case 'A':
161 _WriteString(GetLocaleStr(locale, DAY_1 + cData.wday), hook,
162 locale);
163 break;
165 case 'b':
166 _WriteString(GetLocaleStr(locale,
167 ABMON_1 + cData.month - 1), hook, locale);
168 break;
170 case 'B':
171 _WriteString(GetLocaleStr(locale, MON_1 + cData.month - 1),
172 hook, locale);
173 break;
175 case 'c':
176 FormatDate(locale, "%a %b %d %H:%M:%S %Y", date, hook);
177 break;
179 case 'C':
180 FormatDate(locale, "%a %b %e %T %Z %Y", date, hook);
181 break;
183 case 'd':
184 PrintDigits(cData.mday, '0', 2, hook, locale);
185 break;
187 case 'x':
188 case 'D':
189 FormatDate(locale, "%m/%d/%y", date, hook);
190 break;
192 case 'e':
193 PrintDigits(cData.mday, ' ', 2, hook, locale);
194 break;
196 case 'h':
197 _WriteString(GetLocaleStr(locale,
198 ABMON_1 + cData.month - 1), hook, locale);
199 break;
201 case 'H':
202 PrintDigits(cData.hour, '0', 2, hook, locale);
203 break;
205 case 'I':
206 PrintDigits(cData.hour % 12, '0', 2, hook, locale);
207 break;
209 case 'j':
210 /* TODO: Julian date not tested. */
211 /* Julian date is DDD (1 - 366) */
212 PrintDigits(cData.mday + dayspermonth[cData.month],
213 '0', 3, hook, locale);
214 break;
216 case 'm':
217 PrintDigits(cData.month, '0', 2, hook, locale);
218 break;
220 case 'M':
221 PrintDigits(cData.min, '0', 2, hook, locale);
222 break;
224 case 'n':
225 _WriteChar('\n', hook, locale);
226 break;
228 case 'p':
229 _WriteString(GetLocaleStr(locale,
230 cData.hour < 12 ? AM_STR : PM_STR), hook, locale);
231 break;
233 case 'q':
234 PrintDigits(cData.hour, -1, 2, hook, locale);
235 break;
237 case 'Q':
238 PrintDigits(cData.hour % 12, -1, 2, hook, locale);
239 break;
241 case 'r':
242 FormatDate(locale, "%I:%M:%S %p", date, hook);
243 break;
245 case 'R':
246 FormatDate(locale, "%H:%M", date, hook);
247 break;
249 case 'S':
250 PrintDigits(cData.sec, '0', 2, hook, locale);
251 break;
253 case 't':
254 _WriteChar('\t', hook, locale);
255 break;
257 case 'X':
258 case 'T':
259 FormatDate(locale, "%H:%M:%S", date, hook);
260 break;
262 case 'W': /* week number, Monday first day of week */
263 case 'U': /* week number, Sunday first day of week */
264 days = cData.mday + dayspermonth[cData.month];
266 /* leap year ? */
267 if (0 == (cData.year % 4) && cData.month > 2)
270 ** 1700, 1800, 1900, 2100, 2200 re not leap years.
271 ** 2000 is a leap year.
272 ** -> if a year is divisible by 100 but not by 400 then
273 ** it is not a leap year!
275 if (0 == (cData.year % 100) && 0 != (cData.year % 400))
277 else
278 days++;
282 ** If January 1st is a Monday then the first week
283 ** will start with a Sunday January 7th if Sunday is the first day of the week
284 ** but if Monday is the first day of the week then Jan 1st will also be the
285 ** first day of the first week.
288 ** Go to Saturday = last day of week if Sunday is first day of week
289 ** Go to Sunday = last day of week if Monday is first day of week
291 if ('U' == *formatString)
293 /* Sunday is first day of the week */
294 tmp = days + (6 - cData.wday);
296 else
298 /* Monday is first day of week */
299 if (0 != cData.wday)
300 tmp = days + (7 - cData.wday);
301 else
302 tmp = days;
305 if (tmp < 7)
306 week = 0;
307 else
309 /* cut off the few days that belong to week 0 */
310 tmp -= (tmp % 7);
311 /* Calculate the full amount of weeks */
312 week = tmp / 7;
315 PrintDigits(week, '0', 2, hook, locale);
316 break;
318 case 'w':
319 PrintDigits(cData.wday, -1, 1, hook, locale);
320 break;
322 case 'y':
323 PrintDigits(cData.year % 100, '0', 2, hook, locale);
324 break;
326 case 'Y':
327 PrintDigits(cData.year, '0', 4, hook, locale);
328 break;
330 case 'Z':
331 /* cuurent time zone Unimplemented in 3.1 */
332 break;
334 case 0:
335 break;
337 default:
338 _WriteChar(*formatString, hook, locale);
339 break;
342 else
344 _WriteChar(*formatString, hook, locale);
347 formatString++;
350 _WriteChar(0, hook, locale); /* Write null terminator */
352 CloseLocale(def_locale);
354 AROS_LIBFUNC_EXIT
358 VOID _WriteString(CONST_STRPTR string, const struct Hook *hook,
359 const struct Locale *locale)
361 while (*string != 0)
363 _WriteChar(*string++, hook, locale);
368 VOID _WriteChar(char token, const struct Hook *hook,
369 const struct Locale *locale)
371 AROS_UFC3NR(VOID, hook->h_Entry,
372 AROS_UFCA(const struct Hook *, hook, A0),
373 AROS_UFCA(const struct Locale *, locale, A2),
374 AROS_UFCA(char, token, A1));
378 VOID PrintDigits(UWORD number, char fill, UWORD len,
379 const struct Hook *hook, const struct Locale *locale)
381 char buf[7];
382 char *ptr = &buf[6];
383 int i = 0;
385 buf[6] = 0;
387 while ((number || !i) && i < len)
389 *--ptr = number % 10 + '0';
390 number /= 10;
391 i++;
394 while (len - i > 0 && (char)-1 != fill)
396 len--;
397 _WriteChar(fill, hook, locale);
400 _WriteString((char *)ptr, hook, locale);