2008-09-24 Claudio Saavedra <csaavedra@igalia.com>
[hildon] / src / hildon-date-selector.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2005, 2008 Nokia Corporation.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version. or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free
18  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 /**
22  * SECTION:hildon-date-selector
23  * @short_description: A widget to select the current date.
24  *
25  * HildonDateSelector is a date widget, equivalent to hildon-calendar, but with a multi-column
26  * approach
27  *
28  */
29
30 #define _GNU_SOURCE     /* needed for GNU nl_langinfo_l */
31 #define __USE_GNU       /* needed for locale */
32
33 #include <locale.h>
34
35 #ifdef HAVE_SYS_TIME_H
36 #include <sys/time.h>
37 #endif
38
39 #include <string.h>
40 #include <stdlib.h>
41
42 #include <libintl.h>
43 #include <time.h>
44 #include <langinfo.h>
45
46 #include "hildon-date-selector.h"
47
48 #define HILDON_DATE_SELECTOR_GET_PRIVATE(obj)                           \
49   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), HILDON_TYPE_DATE_SELECTOR, HildonDateSelectorPrivate))
50
51 G_DEFINE_TYPE (HildonDateSelector, hildon_date_selector, HILDON_TYPE_TOUCH_SELECTOR)
52
53 #define INIT_YEAR 100
54 #define LAST_YEAR 50    /* since current year */
55
56 #define _(String) dgettext("hildon-libs", String)
57
58 /* #define _(String) "%A %e. %B %Y"  debug purposes */
59
60 enum
61 {
62   COLUMN_STRING,
63   COLUMN_INT,
64   N_COLUMNS
65 };
66
67 enum
68 {
69   DAY,
70   MONTH,
71   YEAR
72 };
73
74 struct _HildonDateSelectorPrivate
75 {
76   GtkTreeModel *year_model;
77   GtkTreeModel *month_model;
78   GtkTreeModel *day_model;
79
80   GSList *column_order;
81   gint day_column;
82   gint month_column;
83   gint year_column;             /* it depends on the locale */
84
85   gchar *format;                /* day/month/year format, depends on locale */
86
87   gint creation_day;
88   gint creation_month;
89   gint creation_year;           /* date at creation time */
90 };
91
92 static void hildon_date_selector_finalize (GObject * object);
93
94 /* private functions */
95 static GtkTreeModel *_create_day_model (HildonDateSelector * selector);
96 static GtkTreeModel *_create_year_model (HildonDateSelector * selector);
97 static GtkTreeModel *_create_month_model (HildonDateSelector * selector);
98
99 static void _get_real_date (gint * year, gint * month, gint * day);
100 static void _locales_init (HildonDateSelectorPrivate * priv);
101
102 static void _manage_selector_change_cb (HildonTouchSelector * selector,
103                                         gint num_column, gpointer data);
104
105 static GtkTreeModel *_update_day_model (HildonDateSelector * selector);
106
107 static gint _month_days (gint month, gint year);
108 static void _init_column_order (HildonDateSelector * selector);
109
110 static gchar *_custom_print_func (HildonTouchSelector * selector);
111
112 /***************************************************************************/
113 /* The following date routines are taken from the lib_date package.  Keep
114  * them separate in case we want to update them if a newer lib_date comes
115  * out with fixes.  */
116
117 typedef unsigned int N_int;
118
119 typedef unsigned long N_long;
120
121 typedef signed long Z_long;
122
123 typedef enum
124 { false = FALSE, true = TRUE } boolean;
125
126 #define                                         and &&  /* logical (boolean) operators: lower case */
127
128 #define                                         or ||
129
130 static const N_int month_length[2][13] = {
131   {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
132   {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
133 };
134
135 static const N_int days_in_months[2][14] = {
136   {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
137   {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
138 };
139
140 static Z_long _calc_days (N_int year, N_int mm, N_int dd);
141
142 static N_int _day_of_week (N_int year, N_int mm, N_int dd);
143
144 static boolean _leap (N_int year);
145
146
147 static boolean
148 _leap (N_int year)
149 {
150   return ((((year % 4) == 0) and ((year % 100) != 0)) or ((year % 400) == 0));
151 }
152
153 static N_int
154 _day_of_week (N_int year, N_int mm, N_int dd)
155 {
156   Z_long days;
157
158   days = _calc_days (year, mm, dd);
159   if (days > 0L) {
160     days--;
161     days %= 7L;
162     days++;
163   }
164   return ((N_int) days);
165 }
166
167 static Z_long
168 _year_to_days (N_int year)
169 {
170   return (year * 365L + (year / 4) - (year / 100) + (year / 400));
171 }
172
173 static Z_long
174 _calc_days (N_int year, N_int mm, N_int dd)
175 {
176   boolean lp;
177
178   if (year < 1)
179     return (0L);
180   if ((mm < 1) or (mm > 12))
181     return (0L);
182   if ((dd < 1) or (dd > month_length[(lp = _leap (year))][mm]))
183     return (0L);
184   return (_year_to_days (--year) + days_in_months[lp][mm] + dd);
185 }
186
187 static void
188 hildon_date_selector_class_init (HildonDateSelectorClass * class)
189 {
190   GObjectClass *gobject_class;
191   GtkObjectClass *object_class;
192   GtkWidgetClass *widget_class;
193   GtkContainerClass *container_class;
194
195   gobject_class = (GObjectClass *) class;
196   object_class = (GtkObjectClass *) class;
197   widget_class = (GtkWidgetClass *) class;
198   container_class = (GtkContainerClass *) class;
199
200   /* GObject */
201   gobject_class->finalize = hildon_date_selector_finalize;
202
203   /* GtkWidget */
204
205   /* GtkContainer */
206
207   /* signals */
208
209   g_type_class_add_private (object_class, sizeof (HildonDateSelectorPrivate));
210 }
211
212 static void
213 hildon_date_selector_init (HildonDateSelector * selector)
214 {
215   GSList *iter = NULL;
216   gint current_item = 0;
217
218   selector->priv = HILDON_DATE_SELECTOR_GET_PRIVATE (selector);
219
220   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (selector), GTK_NO_WINDOW);
221   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (selector), FALSE);
222
223   hildon_touch_selector_set_print_func (HILDON_TOUCH_SELECTOR (selector),
224                                         _custom_print_func);
225
226   _locales_init (selector->priv);
227
228   _init_column_order (selector);
229
230   _get_real_date (&selector->priv->creation_year,
231                   &selector->priv->creation_month, &selector->priv->creation_day);
232
233   selector->priv->year_model = _create_year_model (selector);
234   selector->priv->month_model = _create_month_model (selector);
235   selector->priv->day_model = _create_day_model (selector);
236
237   /* We add the columns: FIXME: check the locale order */
238   iter = selector->priv->column_order;
239   for (iter = selector->priv->column_order; iter; iter = g_slist_next (iter)) {
240     current_item = GPOINTER_TO_INT (iter->data);
241
242     switch (current_item) {
243     case DAY:
244       hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
245                                                 selector->priv->day_model, TRUE);
246       break;
247     case MONTH:
248       hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
249                                                 selector->priv->month_model, TRUE);
250       break;
251     case YEAR:
252       hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
253                                                 selector->priv->year_model, TRUE);
254       break;
255     default:
256       g_error ("Current column order incorrect");
257       break;
258     }
259   }
260
261   g_signal_connect (G_OBJECT (selector),
262                     "changed", G_CALLBACK (_manage_selector_change_cb), NULL);
263
264   /* By default we should select the current day */
265   hildon_date_selector_select_current_date (selector, selector->priv->creation_year,
266                                             selector->priv->creation_month,
267                                             selector->priv->creation_day);
268 }
269
270 static void
271 hildon_date_selector_finalize (GObject * object)
272 {
273   HildonDateSelector *selector = NULL;
274
275   selector = HILDON_DATE_SELECTOR (object);
276
277   g_slist_free (selector->priv->column_order);
278
279   (*G_OBJECT_CLASS (hildon_date_selector_parent_class)->finalize) (object);
280 }
281
282 /* ------------------------------ PRIVATE METHODS ---------------------------- */
283 static gchar *
284 _custom_print_func (HildonTouchSelector * touch_selector)
285 {
286   HildonDateSelector *selector = NULL;
287   gchar *result = NULL;
288   guint year, month, day;
289   gint day_of_week = 0;
290   static gchar string[255];
291   struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
292
293   selector = HILDON_DATE_SELECTOR (touch_selector);
294
295   hildon_date_selector_get_date (selector, &year, &month, &day);
296   day_of_week = _day_of_week (year, month + 1, day) % 7;
297
298   tm.tm_mday = day;
299   tm.tm_mon = month;
300   tm.tm_year = year - 1900;
301   tm.tm_wday = day_of_week;
302
303   strftime (string, 255, _("wdgt_va_date_long"), &tm);
304
305   result = g_strdup (string);
306
307   return result;
308 }
309
310 /* This was copied from hildon-calendar */
311 static void
312 _locales_init (HildonDateSelectorPrivate * priv)
313 {
314   /* Hildon: This is not exactly portable, see
315    * http://bugzilla.gnome.org/show_bug.cgi?id=343415
316    * The labels need to be instance variables as the startup wizard changes
317    * locale on runtime.
318    */
319   locale_t l;
320
321   l = newlocale (LC_TIME_MASK, setlocale (LC_MESSAGES, NULL), NULL);
322
323   priv->format = g_locale_to_utf8 (nl_langinfo_l (D_FMT, l),
324                                    -1, NULL, NULL, NULL);
325
326   freelocale (l);
327 }
328
329 static void
330 _init_column_order (HildonDateSelector * selector)
331 {
332   gchar *current_order[3] = { NULL, NULL, NULL };
333   gchar *day_pos = NULL;
334   gchar *month_pos = NULL;
335   gchar *year_pos = NULL;
336   gint i, c;
337   gchar *aux = NULL;
338
339   g_debug ("Current format: %s", selector->priv->format);
340
341   /* search each token on the format */
342   day_pos = g_strrstr (selector->priv->format, "%d");
343
344   month_pos = g_strrstr (selector->priv->format, "%m");
345   year_pos = g_strrstr (selector->priv->format, "%y");
346   if (year_pos == NULL) {
347     year_pos = g_strrstr (selector->priv->format, "%Y");
348   }
349
350
351   if ((day_pos == NULL) || (month_pos == NULL) || (year_pos == NULL)) {
352     g_error ("Wrong date format");      /* so default values */
353
354     selector->priv->day_column = 0;
355     selector->priv->month_column = 1;
356     selector->priv->year_column = 2;
357     selector->priv->column_order = g_slist_append (NULL, GINT_TO_POINTER (DAY));
358     selector->priv->column_order =
359       g_slist_append (selector->priv->column_order, GINT_TO_POINTER (MONTH));
360     selector->priv->column_order =
361       g_slist_append (selector->priv->column_order, GINT_TO_POINTER (YEAR));
362   }
363
364   /* sort current_order with this values (bubble sort) */
365   current_order[0] = day_pos;
366   current_order[1] = month_pos;
367   current_order[2] = year_pos;
368
369   for (c = 1; c <= 2; c++) {
370     for (i = 0; i < 3 - c; i++) {
371       if (current_order[i] > current_order[i + 1]) {
372         aux = current_order[i];
373         current_order[i] = current_order[i + 1];
374         current_order[i + 1] = aux;
375       }
376     }
377   }
378
379   /* fill the column positions */
380   selector->priv->column_order = NULL;
381   c = 0;
382   for (i = 0; i < 3; i++) {
383     if (current_order[i] == day_pos) {
384       selector->priv->column_order =
385         g_slist_append (selector->priv->column_order, GINT_TO_POINTER (DAY));
386       selector->priv->day_column = c++;
387     }
388     if (current_order[i] == month_pos) {
389       selector->priv->column_order =
390         g_slist_append (selector->priv->column_order, GINT_TO_POINTER (MONTH));
391       selector->priv->month_column = c++;
392     }
393     if (current_order[i] == year_pos) {
394       selector->priv->column_order =
395         g_slist_append (selector->priv->column_order, GINT_TO_POINTER (YEAR));
396       selector->priv->year_column = c++;
397     }
398   }
399 }
400
401
402 static GtkTreeModel *
403 _create_day_model (HildonDateSelector * selector)
404 {
405   GtkListStore *store_days = NULL;
406   gint i = 0;
407   gchar label[255];
408   struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
409   GtkTreeIter iter;
410
411   store_days = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
412   for (i = 1; i < 32; i++) {
413     tm.tm_mday = i;
414     strftime (label, 255, _("wdgt_va_day_numeric"), &tm);
415
416     gtk_list_store_append (store_days, &iter);
417     gtk_list_store_set (store_days, &iter,
418                         COLUMN_STRING, label, COLUMN_INT, i, -1);
419   }
420
421   return GTK_TREE_MODEL (store_days);
422 }
423
424 static GtkTreeModel *
425 _create_year_model (HildonDateSelector * selector)
426 {
427   GtkListStore *store_years = NULL;
428   gint real_year = 0;
429   gint i = 0;
430   static gchar label[255];
431   struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
432   GtkTreeIter iter;
433
434   real_year = selector->priv->creation_year;
435
436   store_years = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
437   for (i = real_year - INIT_YEAR; i < real_year + LAST_YEAR; i++) {
438     tm.tm_year = i - 1900;
439     strftime (label, 255, _("wdgt_va_year"), &tm);
440
441     gtk_list_store_append (store_years, &iter);
442     gtk_list_store_set (store_years, &iter,
443                         COLUMN_STRING, label, COLUMN_INT, i, -1);
444   }
445
446   return GTK_TREE_MODEL (store_years);
447 }
448
449 static GtkTreeModel *
450 _create_month_model (HildonDateSelector * selector)
451 {
452   GtkTreeIter iter;
453   gint i = 0;
454   GtkListStore *store_months = NULL;
455   static gchar label[255];
456   struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
457
458   store_months = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
459   for (i = 0; i < 12; i++) {
460     tm.tm_mon = i;
461     strftime (label, 255, _("wdgt_va_month"), &tm);
462
463     gtk_list_store_append (store_months, &iter);
464     gtk_list_store_set (store_months, &iter, COLUMN_STRING, label,
465                         COLUMN_INT, i,
466                         -1);
467   }
468
469   return GTK_TREE_MODEL (store_months);
470 }
471
472 static GtkTreeModel *
473 _update_day_model (HildonDateSelector * selector)
474 {
475   GtkListStore *store_days = NULL;
476   gint i = 0;
477   GtkTreeIter iter;
478   static gchar label[255];
479   struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
480   guint current_day = 0;
481   guint current_year = 0;
482   guint current_month = 0;
483   guint num_days = 31;
484
485   hildon_date_selector_get_date (selector, NULL, NULL, &current_day);
486
487   hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
488                                       selector->priv->month_column, &iter);
489   gtk_tree_model_get (selector->priv->month_model,
490                       &iter, COLUMN_INT, &current_month, -1);
491
492   hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
493                                       selector->priv->year_column, &iter);
494   gtk_tree_model_get (selector->priv->year_model,
495                       &iter, COLUMN_INT, &current_year, -1);
496
497   num_days = _month_days (current_month, current_year);
498
499   store_days = GTK_LIST_STORE (selector->priv->day_model);
500   gtk_list_store_clear (store_days);
501
502   for (i = 1; i <= num_days; i++) {
503     tm.tm_mday = i;
504     strftime (label, 255, _("wdgt_va_day_numeric"), &tm);
505
506     gtk_list_store_append (store_days, &iter);
507     gtk_list_store_set (store_days, &iter,
508                         COLUMN_STRING, label, COLUMN_INT, i, -1);
509   }
510
511   /* now we select a day */
512   if (current_day >= num_days) {
513     current_day = num_days;
514   }
515
516   hildon_date_selector_select_day (selector, current_day);
517
518   return GTK_TREE_MODEL (store_days);
519 }
520
521
522 static void
523 _get_real_date (gint * year, gint * month, gint * day)
524 {
525   time_t secs;
526   struct tm *tm = NULL;
527
528   secs = time (NULL);
529   tm = localtime (&secs);
530
531   if (year != NULL) {
532     *year = 1900 + tm->tm_year;
533   }
534
535   if (month != NULL) {
536     *month = tm->tm_mon;
537   }
538
539   if (day != NULL) {
540     *day = tm->tm_mday;
541   }
542 }
543
544
545 static void
546 _manage_selector_change_cb (HildonTouchSelector * touch_selector,
547                             gint num_column, gpointer data)
548 {
549   HildonDateSelector *selector = NULL;
550
551   g_return_if_fail (HILDON_IS_DATE_SELECTOR (touch_selector));
552   selector = HILDON_DATE_SELECTOR (touch_selector);
553
554   if ((num_column == selector->priv->month_column) ||
555       (num_column == selector->priv->year_column)) /* it is required to check that with
556                                                     * the years too,remember: leap years
557                                                     */
558   {
559     _update_day_model (selector);
560   }
561 }
562
563 static gint
564 _month_days (gint month, gint year)
565 {
566   gint month_days[2][12] = {
567     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
568     {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
569   };
570
571   g_return_val_if_fail (month >= 0 && month <= 12, -1);
572
573   return month_days[_leap (year)][month];
574 }
575
576
577 /* ------------------------------ PUBLIC METHODS ---------------------------- */
578
579 /**
580  * hildon_date_selector_new:
581  *
582  * Creates a new #HildonDateSelector
583  *
584  * Returns: a new #HildonDateSelector
585  **/
586 GtkWidget *
587 hildon_date_selector_new ()
588 {
589   return g_object_new (HILDON_TYPE_DATE_SELECTOR, NULL);
590 }
591
592
593 /**
594  * hildon_date_selector_select_date:
595  * @selector: the #HildonDateSelector
596  * @year:  the current year
597  * @month: the current month (0-11)
598  * @day:   the current day (1-31, 1-30, 1-29, 1-28) depends on the month
599  *
600  * Sets the current active date on the #HildonDateSelector widget
601  *
602  **/
603 gboolean
604 hildon_date_selector_select_current_date (HildonDateSelector * selector,
605                                           guint year, guint month, guint day)
606 {
607   GtkTreeIter iter;
608   gint min_year = 0;
609   gint max_year = 0;
610   gint num_days = 0;
611
612   min_year = selector->priv->creation_year - INIT_YEAR;
613   max_year = selector->priv->creation_year + LAST_YEAR;
614
615   g_return_val_if_fail (year > min_year && year < max_year, FALSE);
616   g_return_val_if_fail (month >= 0 && month < 12, FALSE);
617
618   num_days = _month_days (month, year);
619   g_return_val_if_fail (day > 0 && day <= num_days, FALSE);
620
621
622   gtk_tree_model_iter_nth_child (selector->priv->year_model, &iter, NULL,
623                                  year - selector->priv->creation_year +
624                                  INIT_YEAR);
625   hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
626                                      selector->priv->year_column, &iter,
627                                      FALSE);
628
629   gtk_tree_model_iter_nth_child (selector->priv->month_model, &iter, NULL,
630                                  month);
631   hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
632                                      selector->priv->month_column, &iter,
633                                      FALSE);
634
635   gtk_tree_model_iter_nth_child (selector->priv->day_model, &iter, NULL,
636                                  day - 1);
637   hildon_touch_selector_select_iter (HILDON_TOUCH_SELECTOR (selector),
638                                      selector->priv->day_column, &iter,
639                                      FALSE);
640
641   return TRUE;
642 }
643
644
645 /**
646  * hildon_date_selector_get_date:
647  * @selector: the #HildonDateSelector
648  * @year:  to set the current year
649  * @month: to set the current month (0-11)
650  * @day:   to the current day (1-31, 1-30, 1-29, 1-28) depends on the month
651  *
652  * Gets the current active date on the #HildonDateSelector widget
653  *
654  *
655  **/
656 void
657 hildon_date_selector_get_date (HildonDateSelector * selector,
658                                guint * year, guint * month, guint * day)
659 {
660   GtkTreeIter iter;
661
662   if (year != NULL) {
663     hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
664                                         selector->priv->year_column, &iter);
665     gtk_tree_model_get (selector->priv->year_model,
666                         &iter, COLUMN_INT, year, -1);
667   }
668
669   if (month != NULL) {
670     hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
671                                         selector->priv->month_column, &iter);
672     gtk_tree_model_get (selector->priv->month_model,
673                         &iter, COLUMN_INT, month, -1);
674   }
675
676
677   if (day != NULL) {
678     if (hildon_touch_selector_get_selected (HILDON_TOUCH_SELECTOR (selector),
679                                             selector->priv->day_column, &iter))
680     {
681       gtk_tree_model_get (selector->priv->day_model,
682                           &iter, COLUMN_INT, day, -1);
683     }
684 /*       *day = *day - 1;  */
685   }
686
687 }
688
689
690 /**
691  * hildon_date_selector_select_month:
692  * @selector: the #HildonDateSelector
693  * @month: the current month (0-11)
694  * @year:  the current year
695  *
696  * Modify the current month and year on the current active date
697  *
698  * Utility function, too keep this API more similar to the previously existing
699  * hildon-calendar widget.
700  *
701  *
702  **/
703 gboolean hildon_date_selector_select_month (HildonDateSelector *selector,
704                                             guint month, guint year)
705 {
706   guint day = 0;
707
708   hildon_date_selector_get_date (selector, NULL, NULL, &day);
709
710   return hildon_date_selector_select_current_date (selector, year, month, day);
711 }
712
713 /**
714  * hildon_date_selector_select_day:
715  * @selector: the #HildonDateSelector
716  * @day:   the current day (1-31, 1-30, 1-29, 1-28) depends on the month
717  *
718  * Modify the current day on the current active date
719  *
720  * Utility function, too keep this API more similar to the previously existing
721  * hildon-calendar widget.
722  *
723  *
724  **/
725 void
726 hildon_date_selector_select_day (HildonDateSelector *selector, guint day)
727 {
728   guint month = 0;
729   guint year = 0;
730
731   hildon_date_selector_get_date (selector, &year, &month, NULL);
732
733   hildon_date_selector_select_current_date (selector, year, month, day);
734 }