1 /* ************************************************************************** */
2 /* */
3 /* Copyright (C) 2000-2008 Cedric Auger (cedric@grisbi.org) */
4 /* 2003-2008 Benjamin Drieu (bdrieu@april.org) */
5 /* 2009-2018 Pierre Biava (grisbi@pierre.biava.name) */
6 /* https://www.grisbi.org/ */
7 /* */
8 /* This program is free software; you can redistribute it and/or modify */
9 /* it under the terms of the GNU General Public License as published by */
10 /* the Free Software Foundation; either version 2 of the License, or */
11 /* (at your option) any later version. */
12 /* */
13 /* This program is distributed in the hope that it will be useful, */
14 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
15 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
16 /* GNU General Public License for more details. */
17 /* */
18 /* You should have received a copy of the GNU General Public License */
19 /* along with this program; if not, write to the Free Software */
20 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
21 /* */
22 /* ************************************************************************** */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "include.h"
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <glib/gi18n.h>
33 #ifdef G_OS_WIN32
34 #include <winnls.h>
35 #endif
36
37 /*START_INCLUDE*/
38 #include "utils_dates.h"
39 #include "dialog.h"
40 #include "grisbi_win.h"
41 #include "gsb_calendar_entry.h"
42 #include "gsb_form_widget.h"
43 #include "gsb_regex.h"
44 #include "navigation.h"
45 #include "structures.h"
46 #include "utils_str.h"
47 #include "erreur.h"
48 /*END_INCLUDE*/
49
50 /*START_STATIC*/
51 static int gsb_date_get_month_from_string (const gchar *);
52 /*END_STATIC*/
53
54 /*START_EXTERN*/
55 /*END_EXTERN*/
56
57
58 /* date regex:
59 * 1 or 2 digits +
60 * optional (optional separator + 2 digits +
61 * optional (optional separator + 2 or 4 digits))
62 */
63 #define DATE_STRING_REGEX "^(\\d{1,2}|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(?:[-/.:]?(\\d{1,2}|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(?:[-/.:]?(\\d{2}(?:\\d{2})?))?)?$"
64 #define DATE_ISO8601_REGEX "^(2\\d{3})-?(\\d{1,2})?-?(\\d{1,2})?$"
65
66 #define DATE_STRING_KEY "date_string"
67 #define IMP_DATE_STRING_KEY "import_date_string"
68
69
70 /* months */
71 static const gchar *months[] = {
72 "Jan", "Feb", "Mar", "Apr",
73 "May", "Jun", "Jul", "Aug",
74 "Sep", "Oct", "Nov", "Dec"
75 };
76
77 /* format pour les dates */
78 static gchar *import_format = NULL;
79
80 /* test des dates des fichiers csv */
81 static gboolean mismatch_dates = TRUE;
82
83 static const gchar *order_names[] = {
84 "day-month-year",
85 "month-day-year",
86 "year-month-day",
87 "year-day-month",
88 "day-year-month",
89 "month-year-day"
90 };
91
92 /* save of the last date entried */
93 static gchar *last_date = NULL;
94
95 struct struct_last_entry_date {
96 gchar *date_string;
97 GDate *last_entry_date;
98 };
99
100 static struct struct_last_entry_date *buffer_entry_date = NULL;
101
102 /******************************************************************************/
103 /* Private functions */
104 /******************************************************************************/
105 /**
106 *
107 *
108 * \param
109 * \param
110 *
111 * \return
112 **/
gsb_parse_date_string_from_tokens_and_date(gchar ** date_tokens,gchar ** tab_date)113 static GDate *gsb_parse_date_string_from_tokens_and_date (gchar **date_tokens,
114 gchar **tab_date)
115 {
116 GDate *date = NULL;
117 gint num_tokens;
118 gint num_fields;
119 gboolean year_auto;
120 gint page;
121 gint i;
122 gint j;
123 GrisbiWinEtat *w_etat;
124
125 //~ devel_debug (NULL);
126 w_etat = (GrisbiWinEtat *) grisbi_win_get_w_etat ();
127 year_auto = w_etat->form_date_force_prev_year;
128
129 /* Initialize date */
130 date = gdate_today ();
131
132 num_tokens = g_strv_length (date_tokens);
133 num_fields = g_strv_length (tab_date) - 1;
134 for (i = 0, j = 1;
135 i < num_tokens && j < num_fields;
136 i ++, j ++)
137 {
138 /* the string can represent:
139 * EITHER a number (1 for January)
140 * OR a 3-length string (Jan for january)
141 * We assume this is an integer as default behaviour */
142 gint nvalue = atoi (tab_date[j]);
143
144 switch (date_tokens[i][0])
145 {
146 case 'm':
147 /* If month is NOT an integer, nvalue = 0, and we have
148 * to convert month string into an integer. If string is
149 * not valid, the function returns 0 which is not a valid
150 * month -> goto invalid -> right behaviour!!! */
151 if (isalpha (tab_date[j][0]) != 0)
152 nvalue = gsb_date_get_month_from_string (tab_date[j]);
153 if (! g_date_valid_month (nvalue))
154 goto invalid;
155 g_date_set_month (date, nvalue);
156 break;
157
158 case 'd':
159 if (! g_date_valid_day (nvalue))
160 goto invalid;
161 g_date_set_day (date, nvalue);
162 break;
163
164 case 'y':
165 case 'Y':
166 if (strlen (tab_date[j]) == 2
167 || strlen (tab_date[j]) == 1)
168 {
169 if (nvalue < 60)
170 nvalue += 2000;
171 else
172 nvalue += 1900;
173 }
174 if (! g_date_valid_year (nvalue) && num_fields >= 3)
175 goto invalid;
176 g_date_set_year (date, nvalue);
177 break;
178
179 default:
180 g_printerr (">> Unknown format '%s'\n", date_tokens [i]);
181 goto invalid;
182 }
183 }
184
185 /* need here to check if the date is valid, else an error occurs when
186 * write for example only 31, and the current month has only 30 days... */
187 if (! g_date_valid (date))
188 goto invalid;
189
190 /* if page != GSB_SCHEDULER_PAGE && date > today, then we go back one year before
191 * usefull when entering operations just after the new year */
192 page = gsb_gui_navigation_get_current_page ();
193 if (page != GSB_SCHEDULER_PAGE && year_auto)
194 {
195 GDate *today = gdate_today ( );
196 if ( g_date_compare ( today, date ) < 0 )
197 g_date_set_year ( date, g_date_get_year ( today ) - 1 );
198 g_date_free ( today );
199 }
200
201 return date;
202
203 invalid:
204 if (date)
205 g_date_free (date);
206
207 return NULL;
208 }
209
210 /******************************************************************************/
211 /* Public functions */
212 /******************************************************************************/
213 /**
214 * return the last_date if defined, else the date of the day
215 * set last_date if unset
216 *
217 * \param
218 *
219 * \return a string contains the date (DO NOT free this string)
220 **/
gsb_date_today(void)221 gchar *gsb_date_today (void)
222 {
223 if (!last_date)
224 {
225 GDate *date;
226 gchar *date_string;
227
228 date = gdate_today ();
229 date_string = gsb_format_gdate (date);
230 gsb_date_set_last_date (date_string);
231 g_free (date_string);
232 g_date_free (date);
233 }
234 return (last_date);
235 }
236
237 /**
238 * set the last_date value
239 * that value is dumped in memory
240 *
241 * \param a string which contains the last date to remain
242 *
243 **/
gsb_date_set_last_date(const gchar * date)244 void gsb_date_set_last_date (const gchar *date)
245 {
246 g_free (last_date);
247 last_date = my_strdup (date);
248 }
249
250 /**
251 * set last date to null, so the next
252 * call to gsb_date_today will return the today date
253 * and not the last typed
254 *
255 * \param
256 *
257 **/
gsb_date_free_last_date(void)258 void gsb_date_free_last_date (void)
259 {
260 g_free (last_date);
261 last_date = NULL;
262 }
263
264 /**
265 * return the day date in the gdate format
266 *
267 * \param
268 *
269 * \return a newly allocated GDate which represents the date of the day. Use g_date_free to free memory when no more used.
270 **/
gdate_today(void)271 GDate *gdate_today (void)
272 {
273 GDate *date;
274
275 date = g_date_new ();
276 g_date_set_time_t (date, time (NULL));
277 return (date);
278 }
279
280 /**
281 * return the tomorrow date in the gdate format
282 *
283 * \param
284 *
285 * \return a newly allocated GDate which represents the date of the day. Use g_date_free to free memory when no more used.
286 **/
gsb_date_tomorrow(void)287 GDate *gsb_date_tomorrow (void)
288 {
289 GDate *date;
290
291 date = gdate_today ();
292 g_date_add_days (date, 1);
293
294 return (date);
295 }
296
297 /**
298 * adds one month to a date
299 *
300 * \param date
301 * \param free the init date
302 *
303 * \return a newly allocated GDate which represents the date of the day.
304 * Use g_date_free to free memory when no more used.
305 **/
gsb_date_add_one_month(GDate * date,gboolean free)306 GDate *gsb_date_add_one_month (GDate *date,
307 gboolean free)
308 {
309 GDate *new_date;
310
311 new_date = gsb_date_copy (date);
312 g_date_add_months (new_date, 1);
313
314 if (free)
315 g_date_free (date);
316
317 return (new_date);
318 }
319
320 /**
321 * copy the date given in param
322 *
323 * \param date a GDate to copy
324 *
325 * \return a copy or NULL if no date. Use g_date_free to free memory when no more used.
326 **/
gsb_date_copy(const GDate * date)327 GDate *gsb_date_copy (const GDate *date)
328 {
329 GDate *new_date;
330
331 if (!date || !g_date_valid (date))
332 return NULL;
333 #if GLIB_CHECK_VERSION (2,55,0)
334 new_date = g_date_copy (date);
335 #else
336 new_date = g_date_new_dmy (g_date_get_day (date),
337 g_date_get_month (date),
338 g_date_get_year (date));
339 #endif
340
341 return new_date;
342 }
343
344 /**
345 * check the entry to find a date
346 * if the entry is empty, set gsb_date_today according to set_today
347 * if the entry is set, try to understand and fill it if necessary
348 * for example : 1/4/5 becomes 01/04/2005
349 *
350 * \param entry the entry to check
351 * \param set_today if TRUE and the entry is empty, will set into the today date
352 *
353 * \return FALSE if problem with the date, TRUE if ok or entry empty
354 **/
gsb_date_check_and_complete_entry(GtkWidget * entry,gboolean set_today)355 gboolean gsb_date_check_and_complete_entry (GtkWidget *entry,
356 gboolean set_today)
357 {
358 const gchar *string;
359
360 if (!entry)
361 return FALSE;
362
363 /* if the entry is grey (empty), go away */
364 if (gsb_form_widget_check_empty (entry))
365 return (TRUE);
366
367 string = gtk_entry_get_text (GTK_ENTRY (entry));
368 if (!string)
369 return FALSE;
370
371 if (strlen (string))
372 {
373 GDate *date;
374 gchar* tmpstr;
375
376 date = gsb_date_get_last_entry_date (string);
377 if (!date)
378 return FALSE;
379
380 tmpstr = gsb_format_gdate (date);
381 gtk_entry_set_text (GTK_ENTRY (entry), tmpstr);
382 if (buffer_entry_date == NULL)
383 buffer_entry_date = g_malloc0 (sizeof (struct struct_last_entry_date));
384 buffer_entry_date -> date_string = g_strdup (tmpstr);
385 buffer_entry_date -> last_entry_date = date;
386 g_free (tmpstr);
387 }
388 else
389 {
390 if (set_today)
391 gtk_entry_set_text (GTK_ENTRY (entry), gsb_date_today());
392 }
393 return (TRUE);
394 }
395
396 /**
397 * check the date in entry and return TRUE or FALSE
398 *
399 * \param entry an entry containing a date
400 *
401 * \return TRUE date is valid, FALSE date is invalid
402 **/
gsb_date_check_entry(GtkWidget * entry)403 gboolean gsb_date_check_entry (GtkWidget *entry)
404 {
405 const gchar *string;
406 GDate *date;
407
408 if (!entry)
409 return FALSE;
410
411 string = gtk_entry_get_text (GTK_ENTRY (entry));
412 if (!string || strlen (string) == 0)
413 return FALSE;
414
415 date = gsb_date_get_last_entry_date (string);
416 if (!date)
417 return FALSE;
418 else
419 {
420 if (buffer_entry_date == NULL)
421 buffer_entry_date = g_malloc0 (sizeof (struct struct_last_entry_date));
422 buffer_entry_date -> date_string = g_strdup (string);
423 buffer_entry_date -> last_entry_date = date;
424 }
425
426 return (TRUE);
427 }
428
429 /**
430 * Create and try to return a GDate from a string representation of a date.
431 * separator can be "/.-:" and numbers can be stick (ex 01012001)
432 * Moreover, month can be specified as its non-localized string format (ex Jan)
433 *
434 * \param a string which represent a date
435 *
436 * \return a newly allocated gdate or NULL if cannot set
437 **/
gsb_parse_date_string(const gchar * date_string)438 GDate *gsb_parse_date_string (const gchar *date_string)
439 {
440 GDate *date = NULL;
441 GRegex *date_regex;
442 gchar **date_tokens = NULL;
443 gchar **tab_date = NULL;
444 const gchar *regex_str;
445 gchar *format = NULL;
446 GrisbiWinEtat *w_etat;
447
448 //~ devel_debug (date_string);
449 if (!date_string || !strlen (date_string))
450 return NULL;
451
452 w_etat = (GrisbiWinEtat *) grisbi_win_get_w_etat ();
453 format = w_etat->date_format;
454
455 /* set the local pattern */
456 regex_str = DATE_STRING_REGEX;
457
458 /* récupère le format des champs date */
459 if (g_strrstr_len (format, 4, "/%"))
460 date_tokens = g_strsplit (format + 1, "/%", 3);
461 if (g_strrstr_len (format, 4, ".%"))
462 date_tokens = g_strsplit (format + 1, ".%", 3);
463 if (g_strrstr_len (format, 4, "-%"))
464 {
465 date_tokens = g_strsplit (format + 1, "-%", 3);
466 /* set the ISO-8601 pattern */
467 regex_str = DATE_ISO8601_REGEX;
468 }
469 if (NULL == date_tokens)
470 {
471 return NULL;
472 }
473
474 /* get the regex from the store */
475 date_regex = gsb_regex_lookup (DATE_STRING_KEY);
476 if (! date_regex)
477 {
478 /* only for the first call */
479 date_regex = gsb_regex_insert (DATE_STRING_KEY,
480 regex_str,
481 G_REGEX_CASELESS,
482 0);
483 if (! date_regex)
484 {
485 /* big problem */
486 alert_debug (DATE_STRING_KEY);
487 goto invalid;
488 }
489 }
490
491 if (! g_regex_match (date_regex, date_string, 0, NULL))
492 goto invalid;
493
494 tab_date = g_regex_split (date_regex, date_string, 0);
495
496 date = gsb_parse_date_string_from_tokens_and_date (date_tokens, tab_date);
497
498 g_strfreev (tab_date);
499 g_strfreev (date_tokens);
500
501 return date;
502
503 invalid:
504 g_strfreev (tab_date);
505 g_strfreev (date_tokens);
506 return NULL;
507
508 }
509
510 /**
511 * Create and return a GDate from a string locale independant
512 * representation of a date. It expects format %m/%d/%Y (american
513 * style).
514 *
515 * \param
516 *
517 * \return return a newly allocated string or NULL if the format of the date_string
518 * parameter is invalid.
519 **/
gsb_parse_date_string_safe(const gchar * date_string)520 GDate *gsb_parse_date_string_safe (const gchar *date_string)
521 {
522 gchar **tab_date;
523 GDate * date;
524
525 tab_date = g_strsplit (date_string, "/", 3);
526 if (tab_date[0] && tab_date[1] && tab_date[2])
527 {
528 date = g_date_new_dmy (utils_str_atoi (tab_date[1]),
529 utils_str_atoi (tab_date[0]),
530 utils_str_atoi (tab_date[2]));
531 g_strfreev (tab_date);
532 return date;
533 }
534
535 return NULL;
536 }
537
538 /**
539 * Convenience function that return the string representation of a
540 * date based on locale settings.
541 *
542 * \param day Day of the date to represent.
543 * \param month Month of the date to represent.
544 * \param year Year of the date to represent.
545 *
546 * \return A newly allocated string representing date.
547 **/
gsb_format_date(gint day,gint month,gint year)548 gchar *gsb_format_date (gint day,
549 gint month,
550 gint year)
551 {
552 GDate* date;
553 gchar* result;
554
555 date = g_date_new_dmy (day, month, year);
556 result = gsb_format_gdate (date);
557 g_date_free (date);
558
559 return result;
560 }
561
562 /**
563 * Convenience function that return the string representation of a
564 * date based on locale settings.
565 *
566 * \param date A GDate structure containing the date to represent.
567 *
568 * \return A newly allocated string representing date.
569 **/
gsb_format_gdate(const GDate * date)570 gchar *gsb_format_gdate (const GDate *date)
571 {
572 gchar retour_str[SIZEOF_FORMATTED_STRING_DATE];
573 gchar *format = NULL;
574 gsize longueur = 0;
575 GrisbiWinEtat *w_etat;
576
577 if (!date || !g_date_valid (date))
578 return my_strdup ("");
579
580 w_etat = (GrisbiWinEtat *) grisbi_win_get_w_etat ();
581 format = w_etat->date_format;
582
583 if (format)
584 longueur = g_date_strftime (retour_str, SIZEOF_FORMATTED_STRING_DATE, format, date);
585
586 if (longueur == 0)
587 return my_strdup ("");
588 else
589 return g_strndup (retour_str, longueur);
590 }
591
592 /**
593 * Convenience function that return the string representation of a
594 * date without locale. It returns an empty string if date is not valid.
595 *
596 * \param date A GDate structure containing the date to represent.
597 *
598 * \return A newly allocated string representing date.
599 **/
gsb_format_gdate_safe(const GDate * date)600 gchar *gsb_format_gdate_safe (const GDate *date)
601 {
602 gchar retour_str[SIZEOF_FORMATTED_STRING_DATE];
603 gsize longueur;
604
605 if (!date || !g_date_valid (date))
606 {
607 return g_strdup ("");
608 }
609
610 longueur = g_date_strftime (retour_str, SIZEOF_FORMATTED_STRING_DATE, "%m/%d/%Y", date);
611
612 if (longueur == 0)
613 return NULL;
614 else
615 return g_strndup (retour_str, longueur);
616 }
617
618 /**
619 * retourne la date bufferisée si les deux chaines correspondent
620 * sinon renvoie une date issue de la chaine passée en paramètre
621 *
622 * \param
623 *
624 * \return
625 **/
gsb_date_get_last_entry_date(const gchar * string)626 GDate *gsb_date_get_last_entry_date (const gchar *string)
627 {
628 if (buffer_entry_date && g_strcmp0 (string , buffer_entry_date -> date_string) == 0)
629 return gsb_date_copy (buffer_entry_date -> last_entry_date);
630 else
631 return gsb_parse_date_string (string);
632 }
633
634 /**
635 * returns a date with the last day of the month.
636 *
637 * \param
638 *
639 * \return
640 **/
gsb_date_get_last_day_of_month(const GDate * date)641 GDate *gsb_date_get_last_day_of_month (const GDate *date)
642 {
643 GDate *tmp_date;
644
645 tmp_date = gsb_date_copy (date);
646 g_date_set_day (tmp_date, 1);
647 g_date_add_months (tmp_date, 1);
648 g_date_subtract_days (tmp_date, 1);
649
650 return tmp_date;
651 }
652
653 /**
654 * returns the format of date.
655 * The returned string should be freed with g_free() when no longer needed.
656 *
657 * \param
658 *
659 * \return %d/%m/%Y or %m/%d/%Y
660 **/
gsb_date_get_format_date(void)661 gchar *gsb_date_get_format_date (void)
662 {
663 GrisbiWinEtat *w_etat;
664
665 w_etat = (GrisbiWinEtat *) grisbi_win_get_w_etat ();
666 if (w_etat->date_format)
667 return g_strdup (w_etat->date_format);
668 else
669 return NULL;
670 }
671
672 /**
673 * Set the format of date. If given format is not valid, the format
674 * value is set to NULL. Since the format is supposed to change,
675 * the last date entry is erased.
676 *
677 * \param format_date the new format to apply
678 *
679 * \return
680 **/
gsb_date_set_format_date(const gchar * format_date)681 void gsb_date_set_format_date (const gchar *format_date)
682 {
683 GrisbiWinEtat *w_etat;
684
685 devel_debug (NULL);
686 w_etat = (GrisbiWinEtat *) grisbi_win_get_w_etat ();
687 if (w_etat->date_format)
688 {
689 g_free (w_etat->date_format);
690 w_etat->date_format = NULL;
691 }
692
693 if (format_date
694 &&
695 (strcmp (format_date, "%d/%m/%Y") == 0
696 || strcmp (format_date, "%m/%d/%Y") == 0
697 || strcmp (format_date, "%d.%m.%Y") == 0
698 || strcmp (format_date, "%Y-%m-%d") == 0))
699 {
700 w_etat->date_format = g_strdup (format_date);
701 }
702
703 g_free (last_date);
704 last_date = NULL;
705 }
706
707 /**
708 * Returns the integer of the month, as in GDateMonth (ie 1 for January,
709 * ..., 12 for December). This function is case-insensitive.
710 *
711 * \param month A 3-length string representing the month
712 *
713 * \return The integet from 1 to 12, or 0 otherwise
714 **/
gsb_date_get_month_from_string(const gchar * month)715 int gsb_date_get_month_from_string (const gchar *month)
716 {
717 int i;
718 gchar *tmp;
719
720 if (!month)
721 return 0;
722
723 /* first put the case of it is expected:
724 * Uppercase first letter, and lower case for the two remaining */
725 tmp = g_strndup (month, 3);
726 tmp[0] = toupper (tmp[0]);
727 tmp[1] = tolower (tmp[1]);
728 tmp[2] = tolower (tmp[2]);
729
730 /* find the month */
731 for (i = 0; i < 12; i ++)
732 {
733 if (!strcmp (tmp, months[i]))
734 {
735 g_free (tmp);
736 /* return the real month number, so index array + 1 */
737 return i + 1;
738 }
739 }
740
741 g_free (tmp);
742 return 0;
743 }
744
745 /**
746 * returns a the last banking day of the month.
747 *
748 * \param a GDate date
749 *
750 * \return a GDate last banking day of the month
751 *
752 **/
gsb_date_get_last_banking_day_of_month(const GDate * date)753 GDate *gsb_date_get_last_banking_day_of_month (const GDate *date)
754 {
755 GDate *tmp_date;
756 GDateWeekday week_day = G_DATE_BAD_WEEKDAY;
757
758 tmp_date = gsb_date_get_last_day_of_month (date);
759
760 week_day = g_date_get_weekday (tmp_date);
761 switch (week_day)
762 {
763 case G_DATE_SUNDAY :
764 g_date_subtract_days (tmp_date, 2);
765 break;
766 case G_DATE_SATURDAY :
767 g_date_subtract_days (tmp_date, 1);
768 break;
769 case G_DATE_BAD_WEEKDAY:
770 case G_DATE_MONDAY:
771 case G_DATE_TUESDAY:
772 case G_DATE_WEDNESDAY:
773 case G_DATE_THURSDAY:
774 case G_DATE_FRIDAY:
775 break;
776 }
777
778 return tmp_date;
779 }
780
781 /**
782 * retourn la date et l'heure actuelle
783 *
784 * \param with_time si TRUE retourne aussi l'heure
785 *
786 * \return date sous forme de string
787 **/
gsb_date_get_date_time_now_local(void)788 gchar **gsb_date_get_date_time_now_local (void)
789 {
790 GDateTime *datetime;
791 gchar *date_str;
792 gchar *time_str = NULL;
793 gchar **tab;
794 gint year;
795 gint month;
796 gint day;
797 gint hour;
798 gint min;
799 gint sec;
800
801 tab = g_malloc0 (3 * sizeof (gchar *));
802 datetime = g_date_time_new_now_local ();
803 g_date_time_get_ymd (datetime, &year,&month,&day);
804 date_str = gsb_format_date (day, month, year);
805
806 hour = g_date_time_get_hour (datetime);
807 min = g_date_time_get_minute (datetime);
808 sec = g_date_time_get_second (datetime);
809 time_str = g_strdup_printf ("%.2d:%.2d:%.2d", hour,min,sec);
810 tab[0] = date_str;
811 tab[1] = time_str;
812
813 return tab;
814 }
815
816 /**
817 *
818 *
819 * \param
820 *
821 * \return
822 **/
gsb_date_get_first_day_of_current_month(void)823 GDate *gsb_date_get_first_day_of_current_month (void)
824 {
825 GDate *tmp_date;
826
827 tmp_date = gdate_today ();
828 g_date_set_day (tmp_date, 1);
829
830 return tmp_date;
831 }
832 /**
833 *
834 *
835 * \param
836 *
837 * \return
838 **/
gsb_date_set_import_format_date(const GArray * lines_tab,gint index)839 void gsb_date_set_import_format_date (const GArray *lines_tab,
840 gint index)
841 {
842 GSList *list;
843 gint order = 0;
844 gchar *date_wrong[ORDER_MAX];
845 gint num_col_date = -1;
846 gint nbre_dates_OK = 0;
847
848 devel_debug_int (index);
849 mismatch_dates = TRUE;
850 list = g_array_index (lines_tab, GSList *, index);
851 do
852 {
853 gchar **array;
854 gint year = 0, month = 0, day = 0;
855 gint nbre_cols;
856 gint i;
857
858 nbre_cols = g_slist_length (list);
859 for (i = 0; i < nbre_cols; i++)
860 {
861 gchar *tmp_str;
862
863 if (num_col_date == -1)
864 tmp_str = g_slist_nth_data (list, i);
865 else
866 tmp_str = g_slist_nth_data (list, num_col_date);
867
868 array = gsb_date_get_date_content (tmp_str);
869 if (array)
870 {
871 /* get the day, month and year according to the order */
872 switch (order)
873 {
874 case ORDER_DD_MM_YY:
875 day = atoi (array[0]);
876 month = atoi (array[1]);
877 year = atoi (array[2]);
878 break;
879
880 case ORDER_MM_DD_YY:
881 day = atoi (array[1]);
882 month = atoi (array[0]);
883 year = atoi (array[2]);
884 break;
885
886 case ORDER_YY_MM_DD:
887 day = atoi (array[2]);
888 month = atoi (array[1]);
889 year = atoi (array[0]);
890 break;
891
892 case ORDER_YY_DD_MM:
893 day = atoi (array[1]);
894 month = atoi (array[2]);
895 year = atoi (array[0]);
896 break;
897
898 case ORDER_DD_YY_MM:
899 day = atoi (array[0]);
900 month = atoi (array[2]);
901 year = atoi (array[1]);
902 break;
903
904 case ORDER_MM_YY_DD:
905 day = atoi (array[2]);
906 month = atoi (array[0]);
907 year = atoi (array[1]);
908 break;
909 }
910 if (g_date_valid_dmy (day, month, year))
911 {
912 /* the date is valid, go to the next date */
913 num_col_date = i;
914 if (day > 12)
915 nbre_dates_OK ++;
916 g_strfreev (array);
917 break;
918 }
919 else
920 {
921 /* the date is not valid, change the order or go away */
922 date_wrong[order] = (gchar*) list->data;
923 order++;
924
925 if (order < ORDER_MAX)
926 {
927 /* we try again with the new order */
928 nbre_dates_OK = 0;
929 g_strfreev (array);
930 break;
931 }
932 else
933 {
934 /* the order was already changed for all the formats, we show the problem and leave */
935 gint j;
936 gchar *string;
937
938 string = g_strdup (_("The order cannot be determined,\n"));
939
940 for (j = 0; j < ORDER_MAX; j++)
941 {
942 gchar *tmp_str2;
943
944 tmp_str2 = g_strconcat (string,
945 _("Date wrong for the order "),
946 order_names[j], " : ",
947 date_wrong[j], "\n", NULL);
948 g_free (string);
949 string = tmp_str2;
950 }
951
952 dialogue_error (string);
953 g_free (string);
954 g_strfreev (array);
955 import_format = NULL;
956
957 return;
958 }
959 }
960 }
961 else
962 {
963 if (num_col_date >= 0)
964 num_col_date = -1;
965 }
966 }
967 index++;
968 list = g_array_index (lines_tab, GSList *, index);
969 }
970 while (list && nbre_dates_OK < 3);
971
972 switch (order)
973 {
974 case 0:
975 import_format = g_strdup ("%d/%m/%Y");
976 return;
977 break;
978 case 1:
979 import_format = g_strdup ("%m/%d/%Y");
980 return;
981 break;
982 case 2:
983 import_format = g_strdup ("%Y/%m/%d");
984 return;
985 break;
986 case 3:
987 import_format = g_strdup ("%Y/%d/%m");
988 return;
989 break;
990 case 4:
991 import_format = g_strdup ("%d/%Y/%m");
992 return;
993 break;
994 case 5:
995 import_format = g_strdup ("%m/%Y/%d");
996 return;
997 break;
998 }
999 import_format = NULL;
1000 }
1001
1002 /**
1003 * Create and try to return a GDate from a string representation of a date.
1004 * separator can be "/.-:" and numbers can be stick (ex 01012001)
1005 * Moreover, month can be specified as its non-localized string format (ex Jan)
1006 *
1007 * \param a string which represent a date
1008 *
1009 * \return a newly allocated gdate or NULL if cannot set
1010 **/
gsb_parse_import_date_string(const gchar * date_string)1011 GDate *gsb_parse_import_date_string (const gchar *date_string)
1012 {
1013 GDate *date = NULL;
1014 GRegex *date_regex;
1015 gchar **date_tokens = NULL;
1016 gchar **tab_date = NULL;
1017 const gchar *regex_str;
1018
1019 //~ devel_debug (date_string);
1020 if (!date_string || !strlen (date_string))
1021 return NULL;
1022
1023 if (!import_format)
1024 return NULL;
1025
1026 /* set the local pattern */
1027 regex_str = DATE_STRING_REGEX;
1028
1029 /* récupère le format des champs date */
1030 if (g_strrstr_len (import_format, 4, "/%"))
1031 date_tokens = g_strsplit (import_format + 1, "/%", 3);
1032 if (g_strrstr_len (import_format, 4, ".%"))
1033 date_tokens = g_strsplit (import_format + 1, ".%", 3);
1034 if (g_strrstr_len (import_format, 4, "-%"))
1035 {
1036 date_tokens = g_strsplit (import_format + 1, "-%", 3);
1037 /* set the ISO-8601 pattern */
1038 regex_str = DATE_ISO8601_REGEX;
1039 }
1040
1041 if (NULL == date_tokens)
1042 return NULL;
1043
1044 /* get the regex from the store */
1045 date_regex = gsb_regex_lookup (IMP_DATE_STRING_KEY);
1046 if (! date_regex)
1047 {
1048 /* only for the first call */
1049 date_regex = gsb_regex_insert (IMP_DATE_STRING_KEY,
1050 regex_str,
1051 G_REGEX_CASELESS,
1052 0);
1053 if (! date_regex)
1054 {
1055 /* big problem */
1056 alert_debug (IMP_DATE_STRING_KEY);
1057 goto invalid;
1058 }
1059 }
1060
1061 if (! g_regex_match (date_regex, date_string, 0, NULL))
1062 goto invalid;
1063
1064 tab_date = g_regex_split (date_regex, date_string, 0);
1065
1066 date = gsb_parse_date_string_from_tokens_and_date (date_tokens, tab_date);
1067
1068 g_strfreev (tab_date);
1069 g_strfreev (date_tokens);
1070
1071 return date;
1072
1073 invalid:
1074 g_strfreev (tab_date);
1075 g_strfreev (date_tokens);
1076 return NULL;
1077 }
1078
1079 /**
1080 * get a string representing a date and return
1081 * a newly-allocated NULL-terminated array of strings.
1082 * * the order in the array is the same as in the string
1083 *
1084 * \param date_string a -formatted (so randomed...) string
1085 *
1086 * \return a newly-allocated NULL-terminated array of 3 strings. Use g_strfreev() to free it.
1087 **/
gsb_date_get_date_content(const gchar * date_string)1088 gchar **gsb_date_get_date_content (const gchar *date_string)
1089 {
1090 gchar **array;
1091 gchar *tmp_date_string;
1092
1093 //~ devel_debug (date_string);
1094 if (!date_string)
1095 return NULL;
1096
1097 /* some software set a space in the format to annoy us... */
1098 tmp_date_string = my_strdelimit (date_string, " ", "");
1099
1100 array = g_strsplit_set (tmp_date_string, "/.-", 3);
1101 if (g_strv_length (array) == 3)
1102 {
1103 if (mismatch_dates && strlen (array[0]) == 2 && strlen (array[1]) == 2 && strlen (array[2]) == 2)
1104 {
1105 gchar *tmp_str;
1106
1107 tmp_str = g_strdup (_("Warning the date has three fields of two numbers. "
1108 "In these circumstances the date might be wrong."));
1109
1110 dialogue_warning (tmp_str);
1111 g_free (tmp_str);
1112 mismatch_dates = FALSE;
1113 }
1114 g_free (tmp_date_string);
1115
1116 return array;
1117 }
1118 else
1119 {
1120 g_free (tmp_date_string);
1121 return NULL;
1122 }
1123 }
1124
1125 /**
1126 * initialise le format de la date
1127 *
1128 * \param
1129 *
1130 * \return the format date and must be freed
1131 **/
gsb_date_initialise_format_date(void)1132 gchar* gsb_date_initialise_format_date (void)
1133 {
1134 const gchar *langue;
1135
1136 devel_debug (NULL);
1137 langue = g_getenv ("LANG");
1138 if (langue)
1139 {
1140 if (g_str_has_prefix (langue, "en_") || g_str_has_prefix (langue, "cs_"))
1141 return g_strdup ("%m/%d/%Y");
1142 else if (g_str_has_prefix (langue, "de_"))
1143 return g_strdup ("%d.%m.%Y");
1144 else
1145 return g_strdup ("%d/%m/%Y");
1146 }
1147 else
1148 {
1149 return g_strdup ("%d/%m/%Y");
1150 }
1151 }
1152
1153 /**
1154 * Returns the first working day after the date
1155 *
1156 * \param a GDate date
1157 *
1158 * \return a GDate first banking day after the date must be freed
1159 **/
gsb_date_get_first_banking_day_after_date(const GDate * date)1160 GDate *gsb_date_get_first_banking_day_after_date (const GDate *date)
1161 {
1162 GDate *tmp_date;
1163 GDateWeekday week_day = G_DATE_BAD_WEEKDAY;
1164
1165 if (!g_date_valid (date))
1166 tmp_date = gsb_date_get_last_day_of_month (date);
1167 else
1168 tmp_date = gsb_date_copy (date);
1169
1170 week_day = g_date_get_weekday (tmp_date);
1171 switch (week_day)
1172 {
1173 case G_DATE_SUNDAY :
1174 g_date_add_days (tmp_date, 1);
1175 break;
1176 case G_DATE_SATURDAY :
1177 g_date_add_days (tmp_date, 2);
1178 break;
1179 case G_DATE_BAD_WEEKDAY:
1180 case G_DATE_MONDAY:
1181 case G_DATE_TUESDAY:
1182 case G_DATE_WEDNESDAY:
1183 case G_DATE_THURSDAY:
1184 case G_DATE_FRIDAY:
1185 break;
1186 }
1187
1188 return tmp_date;
1189 }
1190
1191 /**
1192 * Returns the first working day before the date
1193 *
1194 * \param a GDate date
1195 *
1196 * \return a GDate first banking day before the date must be freed
1197 **/
gsb_date_get_first_banking_day_before_date(const GDate * date)1198 GDate *gsb_date_get_first_banking_day_before_date (const GDate *date)
1199 {
1200 GDate *tmp_date;
1201 GDateWeekday week_day = G_DATE_BAD_WEEKDAY;
1202
1203 if (!g_date_valid (date))
1204 tmp_date = gsb_date_get_last_day_of_month (date);
1205 else
1206 tmp_date = gsb_date_copy (date);
1207
1208 week_day = g_date_get_weekday (tmp_date);
1209 switch (week_day)
1210 {
1211 case G_DATE_SUNDAY :
1212 g_date_subtract_days (tmp_date, 2);
1213 break;
1214 case G_DATE_SATURDAY :
1215 g_date_subtract_days (tmp_date, 1);
1216 break;
1217 case G_DATE_BAD_WEEKDAY:
1218 case G_DATE_MONDAY:
1219 case G_DATE_TUESDAY:
1220 case G_DATE_WEDNESDAY:
1221 case G_DATE_THURSDAY:
1222 case G_DATE_FRIDAY:
1223 break;
1224 }
1225
1226 return tmp_date;
1227 }
1228
1229 /**
1230 *
1231 *
1232 * \param
1233 *
1234 * \return
1235 **/
1236 /* Local Variables: */
1237 /* c-basic-offset: 4 */
1238 /* End: */
1239