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