// swad_date.c: dates
/*
SWAD (Shared Workspace At a Distance),
is a web platform developed at the University of Granada (Spain),
and used to support university teaching.
This file is part of SWAD core.
Copyright (C) 1999-2019 Antonio Caņas Vargas
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#define _GNU_SOURCE // For vasprintf
#include // For vasprintf
#include // For free
#include // For string functions
#include // For time functions (mktime...)
#include "swad_box.h"
#include "swad_calendar.h"
#include "swad_config.h"
#include "swad_database.h"
#include "swad_date.h"
#include "swad_form.h"
#include "swad_global.h"
#include "swad_HTML.h"
#include "swad_parameter.h"
#include "swad_setting.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/***************************** Public constants ******************************/
/*****************************************************************************/
/*****************************************************************************/
/**************************** Private constants ******************************/
/*****************************************************************************/
const unsigned Dat_NumDaysMonth[1 + 12] =
{
0,
31, // 1: January
28, // 2: February
31, // 3: Mars
30, // 4: April
31, // 5: May
30, // 6: June
31, // 7: July
31, // 8: Agoust
30, // 9: September
31, // 10: October
30, // 11: November
31, // 12: December
};
const char *Dat_TimeStatusClassVisible[Dat_NUM_TIME_STATUS] =
{
"DATE_RED", // Dat_PAST
"DATE_GREEN", // Dat_PRESENT
"DATE_BLUE", // Dat_FUTURE
};
const char *Dat_TimeStatusClassHidden[Dat_NUM_TIME_STATUS] =
{
"DATE_RED_LIGHT", // Dat_PAST
"DATE_GREEN_LIGHT", // Dat_PRESENT
"DATE_BLUE_LIGHT", // Dat_FUTURE
};
/*****************************************************************************/
/****************************** Internal types *******************************/
/*****************************************************************************/
/*****************************************************************************/
/**************************** Private prototypes *****************************/
/*****************************************************************************/
static void Dat_PutIconsDateFormat (void);
static unsigned Dat_GetParamDateFormat (void);
/*****************************************************************************/
/************** Put icons to select the first day of the week ****************/
/*****************************************************************************/
void Dat_PutBoxToSelectDateFormat (void)
{
extern const char *Hlp_PROFILE_Settings_dates;
extern const char *Txt_Dates;
Dat_Format_t Format;
/***** Begin box *****/
Box_BoxBegin (NULL,Txt_Dates,Dat_PutIconsDateFormat,
Hlp_PROFILE_Settings_dates,Box_NOT_CLOSABLE);
/***** Form with list of options *****/
Frm_StartForm (ActChgDatFmt);
HTM_UL_Begin ("class=\"LIST_LEFT\"");
for (Format = (Dat_Format_t) 0;
Format <= (Dat_Format_t) (Dat_NUM_OPTIONS_FORMAT - 1);
Format++)
{
HTM_LI_Begin ("class=\%s\"",(Format == Gbl.Prefs.DateFormat) ? "DAT_N LIGHT_BLUE" :
"DAT");
HTM_LABEL_Begin (NULL);
HTM_INPUT_RADIO ("DateFormat",true,
" value=\"%u\"%s",
(unsigned) Format,
Format == Gbl.Prefs.DateFormat ? " checked=\"checked\"" : "");
Dat_PutSpanDateFormat (Format);
Dat_PutScriptDateFormat (Format);
HTM_LABEL_End ();
HTM_LI_End ();
}
/***** End list *****/
HTM_UL_End ();
/***** End form *****/
Frm_EndForm ();
/***** End box *****/
Box_BoxEnd ();
}
/*****************************************************************************/
/*************** Put contextual icons in date-format setting *****************/
/*****************************************************************************/
static void Dat_PutIconsDateFormat (void)
{
/***** Put icon to show a figure *****/
Gbl.Figures.FigureType = Fig_DATE_FORMAT;
Fig_PutIconToShowFigure ();
}
/*****************************************************************************/
/******* Put script to write current date-time in a given date format ********/
/*****************************************************************************/
void Dat_PutSpanDateFormat (Dat_Format_t Format)
{
fprintf (Gbl.F.Out,"",
(unsigned) Format);
}
void Dat_PutScriptDateFormat (Dat_Format_t Format)
{
char *Id;
if (asprintf (&Id,"date_format_%u",(unsigned) Format) < 0)
Lay_NotEnoughMemoryExit ();
Dat_WriteLocalDateHMSFromUTC (Id,Gbl.StartExecutionTimeUTC,
Format,Dat_SEPARATOR_NONE,
false,true,false,0x0);
free ((void *) Id);
}
/*****************************************************************************/
/***************************** Change date format ****************************/
/*****************************************************************************/
void Dat_ChangeDateFormat (void)
{
/***** Get param with date format *****/
Gbl.Prefs.DateFormat = Dat_GetParamDateFormat ();
/***** Store date format in database *****/
if (Gbl.Usrs.Me.Logged)
DB_QueryUPDATE ("can not update your setting about date format",
"UPDATE usr_data SET DateFormat=%u"
" WHERE UsrCod=%ld",
(unsigned) Gbl.Prefs.DateFormat,
Gbl.Usrs.Me.UsrDat.UsrCod);
/***** Set settings from current IP *****/
Set_SetSettingsFromIP ();
}
/*****************************************************************************/
/********************** Get parameter with date format ***********************/
/*****************************************************************************/
static Dat_Format_t Dat_GetParamDateFormat (void)
{
return (Dat_Format_t) Par_GetParToUnsignedLong ("DateFormat",
0L,
(unsigned long) (Dat_NUM_OPTIONS_FORMAT - 1),
(unsigned long) Dat_FORMAT_DEFAULT);
}
/*****************************************************************************/
/*********************** Get date format from string *************************/
/*****************************************************************************/
Dat_Format_t Dat_GetDateFormatFromStr (const char *Str)
{
unsigned UnsignedNum;
if (sscanf (Str,"%u",&UnsignedNum) == 1)
if (UnsignedNum < Dat_NUM_OPTIONS_FORMAT)
return (Dat_Format_t) UnsignedNum;
return Dat_FORMAT_DEFAULT;
}
/*****************************************************************************/
/************************** Get current time UTC *****************************/
/*****************************************************************************/
void Dat_GetStartExecutionTimeUTC (void)
{
Gbl.StartExecutionTimeUTC = time (NULL);
}
/*****************************************************************************/
/********************** Get and convert current time *************************/
/*****************************************************************************/
void Dat_GetAndConvertCurrentDateTime (void)
{
struct tm *tm_ptr;
/***** Convert current local time to a struct tblock *****/
tm_ptr = Dat_GetLocalTimeFromClock (&Gbl.StartExecutionTimeUTC);
Gbl.Now.Date.Year = tm_ptr->tm_year + 1900;
Gbl.Now.Date.Month = tm_ptr->tm_mon + 1;
Gbl.Now.Date.Day = tm_ptr->tm_mday;
Gbl.Now.Time.Hour = tm_ptr->tm_hour;
Gbl.Now.Time.Minute = tm_ptr->tm_min;
Gbl.Now.Time.Second = tm_ptr->tm_sec;
/***** Initialize current date in format YYYYMMDD *****/
snprintf (Gbl.Now.Date.YYYYMMDD,sizeof (Gbl.Now.Date.YYYYMMDD),
"%04u%02u%02u",
Gbl.Now.Date.Year,Gbl.Now.Date.Month,Gbl.Now.Date.Day);
/***** Initialize current time in format YYYYMMDDHHMMSS *****/
snprintf (Gbl.Now.YYYYMMDDHHMMSS,sizeof (Gbl.Now.YYYYMMDDHHMMSS),
"%04u%02u%02u%02u%02u%02u",
Gbl.Now.Date.Year,Gbl.Now.Date.Month,Gbl.Now.Date.Day,
Gbl.Now.Time.Hour,Gbl.Now.Time.Minute,Gbl.Now.Time.Second);
/***** Compute what day was yesterday *****/
Dat_GetDateBefore (&Gbl.Now.Date,&Gbl.Yesterday);
}
/*****************************************************************************/
/************ Get UNIX time (seconds since 1970 UTC) from string *************/
/*****************************************************************************/
time_t Dat_GetUNIXTimeFromStr (const char *Str)
{
time_t Time = (time_t) 0;
if (Str)
if (Str[0])
if (sscanf (Str,"%ld",&Time) != 1)
Time = (time_t) 0;
return Time;
}
/*****************************************************************************/
/*********** Get a struct Date from a string in YYYYMMDD format **************/
/*****************************************************************************/
bool Dat_GetDateFromYYYYMMDD (struct Date *Date,const char *YYYYMMDD)
{
if (YYYYMMDD)
if (YYYYMMDD[0])
if (sscanf (YYYYMMDD,"%04u%02u%02u",&(Date->Year),&(Date->Month),&(Date->Day)) == 3)
{
Str_Copy (Date->YYYYMMDD,YYYYMMDD,
Dat_LENGTH_YYYYMMDD);
return true;
}
Date->Year = Date->Month = Date->Day = 0;
Date->YYYYMMDD[0] = '\0';
return false;
}
/*****************************************************************************/
/******************** Write div for client local time ************************/
/*****************************************************************************/
void Dat_ShowClientLocalTime (void)
{
extern const char *Txt_Show_calendar;
extern const char *Txt_Show_agenda;
/***** Draw the current date and time *****/
/* Start container */
HTM_DIV_Begin ("id=\"current_date\"");
/* Month with link to calendar */
HTM_DIV_Begin ("id=\"current_month\"");
Frm_StartForm (ActSeeCal);
Frm_LinkFormSubmit (Txt_Show_calendar,"CURRENT_MONTH",NULL);
fprintf (Gbl.F.Out,"" // JavaScript will write HTML here
"");
Frm_LinkFormEnd ();
Frm_EndForm ();
HTM_DIV_End ();
/* Day with link to agenda (if I am logged) */
HTM_DIV_Begin ("id=\"current_day\"");
if (Gbl.Usrs.Me.Logged)
{
Frm_StartForm (ActSeeMyAgd);
Frm_LinkFormSubmit (Txt_Show_agenda,"CURRENT_DAY",NULL);
}
fprintf (Gbl.F.Out,"" // JavaScript will write HTML here
"");
if (Gbl.Usrs.Me.Logged)
{
Frm_LinkFormEnd ();
Frm_EndForm ();
}
HTM_DIV_End ();
/* Time */
HTM_DIV_Begin ("id=\"current_time\""); // JavaScript will write HTML here
HTM_DIV_End ();
/* End container */
HTM_DIV_End ();
/* Write script to draw the month */
HTM_SCRIPT_Begin (NULL,NULL);
fprintf (Gbl.F.Out,"secondsSince1970UTC = %ld;\n"
"writeLocalClock();\n",
(long) Gbl.StartExecutionTimeUTC);
HTM_SCRIPT_End ();
}
/*****************************************************************************/
/***************** Compute local time, adjusting day of week *****************/
/*****************************************************************************/
struct tm *Dat_GetLocalTimeFromClock (const time_t *timep)
{
struct tm *tm_ptr;
if ((tm_ptr = localtime (timep)) == NULL)
Lay_ShowErrorAndExit ("Can not get local time from clock.");
/***** Convert from sunday, monday, tuesday...
to monday, tuesday, wednesday... *****/
if (tm_ptr->tm_wday == 0) // sunday
tm_ptr->tm_wday = 6;
else if (tm_ptr->tm_wday >= 1 &&
tm_ptr->tm_wday <= 6) // monday to saturday
tm_ptr->tm_wday--;
else // error!
tm_ptr->tm_wday = 0;
return tm_ptr;
}
/*****************************************************************************/
/********* Convert a struct with Day, Month and Year to a date string ********/
/*****************************************************************************/
void Dat_ConvDateToDateStr (struct Date *Date,char StrDate[Cns_MAX_BYTES_DATE + 1])
{
extern const char *Txt_MONTHS_SMALL_SHORT[12];
if (Date->Day == 0 ||
Date->Month == 0 ||
Date->Year == 0)
StrDate[0] = '\0';
else
switch (Gbl.Prefs.DateFormat)
{
case Dat_FORMAT_YYYY_MM_DD:
snprintf (StrDate,Cns_MAX_BYTES_DATE + 1,
"%04u-%02u-%02u",
Date->Year,
Date->Month,
Date->Day);
break;
case Dat_FORMAT_DD_MONTH_YYYY:
snprintf (StrDate,Cns_MAX_BYTES_DATE + 1,
"%u %s %04u",
Date->Day,
Txt_MONTHS_SMALL_SHORT[Date->Month - 1],
Date->Year);
break;
case Dat_FORMAT_MONTH_DD_YYYY:
snprintf (StrDate,Cns_MAX_BYTES_DATE + 1,
"%s %u, %04u",
Txt_MONTHS_SMALL_SHORT[Date->Month - 1],
Date->Day,
Date->Year);
break;
}
}
/*****************************************************************************/
/*************** Show forms to enter initial and ending dates ****************/
/*****************************************************************************/
void Dat_PutFormStartEndClientLocalDateTimesWithYesterdayToday (bool SetHMS000000To235959)
{
extern const char *The_ClassFormInBox[The_NUM_THEMES];
extern const char *Txt_START_END_TIME[Dat_NUM_START_END_TIME];
extern const char *Txt_Yesterday;
extern const char *Txt_Today;
HTM_TR_Begin (NULL);
/***** Start date-time *****/
HTM_TD_Begin ("class=\"RM\"");
HTM_LABEL_Begin ("class=\"%s\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
fprintf (Gbl.F.Out,"%s:",Txt_START_END_TIME[Dat_START_TIME]);
HTM_LABEL_End ();
HTM_TD_End ();
/* Date-time */
HTM_TD_Begin ("class=\"LM\"");
Dat_WriteFormClientLocalDateTimeFromTimeUTC ("Start",
"Start",
Gbl.DateRange.TimeUTC[0],
Cfg_LOG_START_YEAR,
Gbl.Now.Date.Year,
Dat_FORM_SECONDS_ON,
SetHMS000000To235959 ? Dat_HMS_TO_000000 : // Set hour, minute and second to 00:00:00
Dat_HMS_DO_NOT_SET, // Don't set hour, minute and second to 00:00:00
false); // Don't submit on change
HTM_TD_End ();
/***** "Yesterday" and "Today" buttons *****/
HTM_TD_Begin ("rowspan=\"2\" class=\"LM\"");
HTM_INPUT_BUTTON ("Yesterday",Txt_Yesterday,
"onclick=\"setDateToYesterday('Start','End');\"");
HTM_INPUT_BUTTON ("Today",Txt_Today,
"onclick=\"setDateToToday('Start','End');\"");
HTM_TD_End ();
HTM_TR_End ();
HTM_TR_Begin (NULL);
/***** End date-time *****/
HTM_TD_Begin ("class=\"RM\"");
HTM_LABEL_Begin ("class=\"%s\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
fprintf (Gbl.F.Out,"%s:",Txt_START_END_TIME[Dat_END_TIME]);
HTM_LABEL_End ();
HTM_TD_End ();
/* Date-time */
HTM_TD_Begin ("class=\"LM\"");
Dat_WriteFormClientLocalDateTimeFromTimeUTC ("End",
"End",
Gbl.DateRange.TimeUTC[1],
Cfg_LOG_START_YEAR,
Gbl.Now.Date.Year,
Dat_FORM_SECONDS_ON,
SetHMS000000To235959 ? Dat_HMS_TO_235959 : // Set hour, minute and second to 23:59:59
Dat_HMS_DO_NOT_SET, // Don't set hour, minute and second
false); // Don't submit on change
HTM_TD_End ();
HTM_TR_End ();
}
/*****************************************************************************/
/************* Show forms to enter initial and ending date-times *************/
/*****************************************************************************/
void Dat_PutFormStartEndClientLocalDateTimes (time_t TimeUTC[2],
Dat_FormSeconds FormSeconds)
{
extern const char *The_ClassFormInBox[The_NUM_THEMES];
extern const char *Txt_START_END_TIME[Dat_NUM_START_END_TIME];
Dat_StartEndTime_t StartEndTime;
const char *Id[Dat_NUM_START_END_TIME] =
{
"Start", // Dat_START_TIME
"End" // Dat_END_TIME
};
for (StartEndTime = Dat_START_TIME;
StartEndTime <= Dat_END_TIME;
StartEndTime++)
{
/* Date-time */
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"RM\"");
HTM_LABEL_Begin ("class=\"%s\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
fprintf (Gbl.F.Out,"%s:",Txt_START_END_TIME[StartEndTime]);
HTM_LABEL_End ();
HTM_TD_End ();
HTM_TD_Begin ("class=\"LM\"");
Dat_WriteFormClientLocalDateTimeFromTimeUTC (Id[StartEndTime],
Id[StartEndTime],
TimeUTC[StartEndTime],
Gbl.Now.Date.Year - 1,
Gbl.Now.Date.Year + 1,
FormSeconds,
Dat_HMS_DO_NOT_SET, // Don't set hour, minute and second
false); // Don't submit on change
HTM_TD_End ();
HTM_TR_End ();
}
}
/*****************************************************************************/
/************************* Show a form to enter a date ***********************/
/*****************************************************************************/
void Dat_WriteFormClientLocalDateTimeFromTimeUTC (const char *Id,
const char *ParamName,
time_t TimeUTC,
unsigned FirstYear,
unsigned LastYear,
Dat_FormSeconds FormSeconds,
Dat_SetHMS SetHMS,
bool SubmitFormOnChange)
{
extern const char *Txt_MONTHS_SMALL[12];
unsigned Day;
unsigned Month;
unsigned Year;
unsigned Hour;
unsigned Minute;
unsigned Second;
unsigned MinutesIInterval[Dat_NUM_FORM_SECONDS] =
{
5, // Dat_FORM_SECONDS_OFF
1, // Dat_FORM_SECONDS_ON
};
char *ParamTimeUTC;
/***** Begin table *****/
HTM_TABLE_Begin (NULL);
HTM_TR_Begin (NULL);
/***** Year *****/
HTM_TD_Begin ("class=\"RM\"");
fprintf (Gbl.F.Out,"