Skip to content
Snippets Groups Projects
Commit 83607285 authored by Rob Swindell's avatar Rob Swindell :speech_balloon:
Browse files

Introduce 3rd system/local date display format: YY/MM/DD

... and YYYY/MM/DD for birthdate input/display.

Now set in SCFG->System (not toggle options) and stored in the "date_fmt" key
(new) in main.ini. The old sys_misc SM_EURODATE flag is deprecated (but used
to determine the default value of date_fmt when not present).

As requested from: Max (WESTLINE)

  Is it possible to do a new dateformat in scfg
  In sweden we using YYYY-MM-DD format as standard.
parent e51b497c
No related branches found
No related tags found
No related merge requests found
Pipeline #5184 passed
......@@ -712,7 +712,7 @@ const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode,
}
if(strcmp(sp, "DATEFMT") == 0) {
return cfg.sys_misc&SM_EURODATE ? "DD/MM/YY" : "MM/DD/YY";
return date_format(&cfg);
}
if(strcmp(sp, "BDATEFMT") == 0 || strcmp(sp, "BIRTHFMT") == 0) {
......
......@@ -26,6 +26,20 @@ const char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
const char *mon[]={"Jan","Feb","Mar","Apr","May","Jun"
,"Jul","Aug","Sep","Oct","Nov","Dec"};
/****************************************************************************/
/****************************************************************************/
const char* date_format(scfg_t* cfg)
{
switch (cfg->sys_date_fmt) {
case DDMMYY: return "DD/MM/YY";
case MMDDYY: return "MM/DD/YY";
case YYMMDD: return "YY/MM/DD";
}
return "????????";
}
#define DECVAL(ch, mul) (DEC_CHAR_TO_INT(ch) * (mul))
/****************************************************************************/
/* Converts a date string in format MM/DD/YY into unix time format */
/****************************************************************************/
......@@ -60,10 +74,13 @@ time32_t dstrtounix(scfg_t* cfg, const char *instr)
}
memset(&tm,0,sizeof(tm));
if (cfg->sys_date_fmt == YYMMDD) {
tm.tm_year = DECVAL(p[0], 10) + DECVAL(p[1], 1);
tm.tm_mon = DECVAL(p[3], 10) + DECVAL(p[4], 1);
tm.tm_mday = DECVAL(p[6], 10) + DECVAL(p[7], 1);
} else {
tm.tm_year=((p[6]&0xf)*10)+(p[7]&0xf);
if (tm.tm_year<Y2K_2DIGIT_WINDOW)
tm.tm_year+=100;
if(cfg->sys_misc&SM_EURODATE) {
if(cfg->sys_date_fmt == DDMMYY) {
tm.tm_mon=((p[3]&0xf)*10)+(p[4]&0xf);
tm.tm_mday=((p[0]&0xf)*10)+(p[1]&0xf);
}
......@@ -71,6 +88,9 @@ time32_t dstrtounix(scfg_t* cfg, const char *instr)
tm.tm_mon=((p[0]&0xf)*10)+(p[1]&0xf);
tm.tm_mday=((p[3]&0xf)*10)+(p[4]&0xf);
}
}
if (tm.tm_year<Y2K_2DIGIT_WINDOW)
tm.tm_year+=100;
if (tm.tm_mon)
tm.tm_mon--; /* zero-based month field */
tm.tm_isdst=-1; /* Do not adjust for DST */
......@@ -98,7 +118,10 @@ char* unixtodstr(scfg_t* cfg, time32_t t, char *str)
}
if(tm.tm_mday>31)
tm.tm_mday=1;
if(cfg->sys_misc&SM_EURODATE)
if (cfg->sys_date_fmt == YYMMDD)
sprintf(str,"%02u/%02u/%02u"
,TM_YEAR(tm.tm_year), tm.tm_mon+1, tm.tm_mday);
else if(cfg->sys_date_fmt == DDMMYY)
sprintf(str,"%02u/%02u/%02u",tm.tm_mday,tm.tm_mon+1
,TM_YEAR(tm.tm_year));
else
......
......@@ -32,6 +32,7 @@ extern "C" {
extern const char* wday[]; /* abbreviated weekday names */
extern const char* mon[]; /* abbreviated month names */
DLLEXPORT const char* date_format(scfg_t*);
DLLEXPORT char * zonestr(short zone);
DLLEXPORT time32_t dstrtounix(scfg_t*, const char *str);
DLLEXPORT char * unixtodstr(scfg_t*, time32_t, char *str);
......
......@@ -283,7 +283,7 @@ BOOL sbbs_t::newuser()
while((cfg.uq&UQ_BIRTH) && online && text[EnterYourBirthday][0]) {
bprintf(text[EnterYourBirthday], birthdate_format(&cfg));
format_birthdate(&cfg, useron.birth, str, sizeof(str));
if(gettmplt(str, "nn/nn/nnnn", K_EDIT) < 10)
if(gettmplt(str, cfg.sys_date_fmt == YYMMDD ? "nnnn/nn/nn" : "nn/nn/nnnn", K_EDIT) < 10)
continue;
int age = getage(&cfg, parse_birthdate(&cfg, str, tmp, sizeof(tmp)));
if(age >= 0 && age <= 200) { // TODO: Configurable min/max user age
......
......@@ -132,7 +132,7 @@
| UQ_REALNAME)
// Different bits in sys_misc
#define SM_CLOSED (1<<0) // System is clsoed to New Users
#define SM_CLOSED (1<<0) // System is closed to New Users
#define SM_SYSSTAT (1<<1) // Sysops activity included in statistics
#define SM_NOSYSINFO (1<<2) // Suppress system info display at logon
#define SM_PWEDIT (1<<3) // Allow users to change their passwords
......@@ -149,7 +149,7 @@
#define SM_AUTO_DST (1<<14) // Automatic Daylight Savings Toggle (US)
#define SM_R_SYSOP (1<<15) // Allow remote sysop login/commands
#define SM_QUOTE_EM (1<<16) // Allow quoting of e-mail
#define SM_EURODATE (1<<17) // European date format (DD/MM/YY)
#define SM_EURODATE (1<<17) // European date format (DD/MM/YY) - DEPRECATED
#define SM_MILITARY (1<<18) // Military (24hr) time format
#define SM_TIMEBANK (1<<19) // Allow time bank functions
#define SM_FILE_EM (1<<20) // Allow file attachments in E-mail
......
......@@ -1315,23 +1315,22 @@ int edit_sys_timefmt(int page, int total)
int edit_sys_datefmt(int page, int total)
{
int mode = WIN_SAV | WIN_MID;
int i = (cfg.sys_misc & SM_EURODATE) ? 1:0;
char* opts[3] = { "MM/DD/YY", "DD/MM/YY", NULL };
int i = cfg.sys_date_fmt;
char* opts[] = { "MM/DD/YY", "DD/MM/YY", "YY/MM/DD", NULL };
uifc.helpbuf=
"`Date Display Format:`\n"
"\n"
"If you would like abbreviated dates to be displayed in the traditional\n"
"U.S. date format of month first, choose `MM/DD/YY`. If you prefer the\n"
"European traditional date format of day first, choose `DD/MM/YY`.\n"
"If you and your users would prefer year first, choose `YY/MM/DD`.\n"
;
if(page)
mode = wiz_help(page, total, uifc.helpbuf);
i=uifc.list(mode,0,10,0,&i,0
,"Date Display Format", opts);
if(i == 0)
cfg.sys_misc &= ~SM_EURODATE;
else if(i == 1)
cfg.sys_misc |= SM_EURODATE;
if(i >= 0)
cfg.sys_date_fmt = i;
return i;
}
......@@ -1656,6 +1655,7 @@ void sys_cfg(void)
snprintf(opt[i++],MAX_OPLN,"%-20s%s %s","Local Time Zone"
,smb_zonestr(cfg.sys_timezone,NULL)
,SMB_TZ_HAS_DST(cfg.sys_timezone) && cfg.sys_misc&SM_AUTO_DST ? "(Auto-DST)" : "");
snprintf(opt[i++],MAX_OPLN,"%-20s%s","Local Date Format", date_format(&cfg));
snprintf(opt[i++],MAX_OPLN,"%-20s%s","Operator",cfg.sys_op);
strcpy(opt[i++],"Notifications...");
......@@ -1698,12 +1698,15 @@ void sys_cfg(void)
edit_sys_timezone(false, false);
break;
case 3:
edit_sys_operator(false, false);
edit_sys_datefmt(false, false);
break;
case 4:
edit_sys_operator(false, false);
break;
case 5:
cfg_notify();
break;
case 5: /* Toggle Options */
case 6: /* Toggle Options */
done=0;
while(!done) {
i=0;
......@@ -1721,8 +1724,6 @@ void sys_cfg(void)
,cfg.sys_misc&SM_LISTLOC ? "Yes" : "No");
snprintf(opt[i++], MAX_OPLN, "%-33.33s%s","Military (24 hour) Time Format"
,cfg.sys_misc&SM_MILITARY ? "Yes" : "No");
snprintf(opt[i++], MAX_OPLN, "%-33.33s%s","European Date Format (DD/MM/YY)"
,cfg.sys_misc&SM_EURODATE ? "Yes" : "No");
snprintf(opt[i++], MAX_OPLN, "%-33.33s%s","Display Sys Info During Logon"
,cfg.sys_misc&SM_NOSYSINFO ? "No" : "Yes");
snprintf(opt[i++], MAX_OPLN, "%-33.33s%s","Display Node List During Logon"
......@@ -1841,9 +1842,6 @@ void sys_cfg(void)
edit_sys_timefmt(false, false);
break;
case 7:
edit_sys_datefmt(false, false);
break;
case 8:
i=cfg.sys_misc&SM_NOSYSINFO ? 1:0;
uifc.helpbuf=
"`Display System Information During Logon:`\n"
......@@ -1860,7 +1858,7 @@ void sys_cfg(void)
cfg.sys_misc|=SM_NOSYSINFO;
}
break;
case 9:
case 8:
i=cfg.sys_misc&SM_NONODELIST ? 1:0;
uifc.helpbuf=
"`Display Active Node List During Logon:`\n"
......@@ -1880,7 +1878,7 @@ void sys_cfg(void)
}
}
break;
case 6: /* New User Values */
case 7: /* New User Values */
done=0;
while(!done) {
i=0;
......@@ -2260,7 +2258,7 @@ void sys_cfg(void)
}
}
break;
case 7:
case 8:
uifc.helpbuf=
"`New User Questions/Prompts:`\n"
"\n"
......@@ -2393,10 +2391,10 @@ void sys_cfg(void)
}
}
break;
case 8:
case 9:
security_cfg();
break;
case 9: /* Advanced Options */
case 10: /* Advanced Options */
done=0;
while(!done) {
i=0;
......@@ -2827,7 +2825,7 @@ void sys_cfg(void)
}
}
break;
case 10: /* Loadable Modules */
case 11: /* Loadable Modules */
done=0;
while(!done) {
i=0;
......
......@@ -384,6 +384,8 @@ struct mqtt_cfg {
} tls;
};
enum date_fmt { MMDDYY, DDMMYY, YYMMDD };
typedef struct
{
DWORD size; /* sizeof(scfg_t) */
......@@ -460,6 +462,7 @@ typedef struct
char sys_inetaddr[128]; /* System's internet address */
char sys_location[41]; /* System Location */
int16_t sys_timezone; /* Time Zone of BBS */
enum date_fmt sys_date_fmt;
char sys_daily[LEN_CMD+1]; /* Daily event */
char sys_logon[LEN_CMD+1]; /* Logon event */
char sys_logout[LEN_CMD+1]; /* Logoff event */
......
......@@ -102,6 +102,7 @@ BOOL read_main_cfg(scfg_t* cfg, char* error, size_t maxerrlen)
cfg->sys_timezone = iniGetInt16(ini, ROOT_SECTION, "timezone", 0);
cfg->sys_misc = iniGetUInteger(ini, ROOT_SECTION, "settings", 0);
cfg->sys_date_fmt = iniGetInteger(ini, ROOT_SECTION, "date_fmt", cfg->sys_misc & SM_EURODATE ? DDMMYY : MMDDYY);
cfg->sys_login = iniGetUInteger(ini, ROOT_SECTION, "login", 0);
cfg->sys_pwdays = iniGetInteger(ini, ROOT_SECTION, "pwdays", 0);
cfg->sys_deldays = iniGetInteger(ini, ROOT_SECTION, "deldays", 0);
......
......@@ -122,6 +122,7 @@ BOOL write_main_cfg(scfg_t* cfg)
iniSetUInteger(&ini, ROOT_SECTION, "password_timeout", cfg->sys_pass_timeout, NULL);
iniSetInt16(&ini, ROOT_SECTION, "timezone", cfg->sys_timezone, NULL);
iniSetHexInt(&ini, ROOT_SECTION, "settings", cfg->sys_misc, NULL);
iniSetUInteger(&ini, ROOT_SECTION, "date_fmt", cfg->sys_date_fmt, NULL);
iniSetHexInt(&ini, ROOT_SECTION, "login", cfg->sys_login, NULL);
iniSetUInteger(&ini, ROOT_SECTION, "lastnode", cfg->sys_lastnode, NULL);
iniSetUInteger(&ini, ROOT_SECTION, "pwdays", cfg->sys_pwdays, NULL);
......
......@@ -953,9 +953,21 @@ char* getbirthddmmyy(scfg_t* cfg, const char* birth, char* buf, size_t max)
return buf;
}
// Always returns string in YY/MM/DD format
char* getbirthyymmdd(scfg_t* cfg, const char* birth, char* buf, size_t max)
{
safe_snprintf(buf, max, "%02u/%02u/%02u"
, getbirthyear(birth) % 100
, getbirthmonth(cfg, birth)
, getbirthday(cfg, birth));
return buf;
}
char* getbirthdstr(scfg_t* cfg, const char* birth, char* buf, size_t max)
{
if(cfg->sys_misc & SM_EURODATE)
if(cfg->sys_date_fmt == YYMMDD)
getbirthyymmdd(cfg, birth, buf, max);
else if(cfg->sys_date_fmt == DDMMYY)
getbirthddmmyy(cfg, birth, buf, max);
else
getbirthmmddyy(cfg, birth, buf, max);
......@@ -991,11 +1003,13 @@ int getage(scfg_t* cfg, const char *birth)
}
/****************************************************************************/
/* Converts from either MM/DD/YYYYY or DD/MM/YYYY to YYYYMMDD */
/* Converts from MM/DD/YYYYY, DD/MM/YYYY, or YYYY/MM/DD to YYYYMMDD */
/****************************************************************************/
char* parse_birthdate(scfg_t* cfg, const char* birthdate, char* out, size_t maxlen)
{
if(cfg->sys_misc & SM_EURODATE)
if (cfg->sys_date_fmt == YYMMDD)
safe_snprintf(out, maxlen, "%.4s%.2s%.2s", birthdate, birthdate + 3, birthdate + 6);
else if (cfg->sys_date_fmt == DDMMYY)
safe_snprintf(out, maxlen, "%.4s%.2s%.2s", birthdate + 6, birthdate + 3, birthdate);
else
safe_snprintf(out, maxlen, "%.4s%.2s%.2s", birthdate + 6, birthdate, birthdate + 3);
......@@ -1003,7 +1017,7 @@ char* parse_birthdate(scfg_t* cfg, const char* birthdate, char* out, size_t maxl
}
/****************************************************************************/
/* Converts from user birth date to either MM/DD/YYYYY or DD/MM/YYYY */
/* Converts from user birth date to MM/DD/YYYYY, DD/MM/YYYY, or YYYY/MM/DD */
/****************************************************************************/
char* format_birthdate(scfg_t* cfg, const char* birthdate, char* out, size_t maxlen)
{
......@@ -1011,7 +1025,10 @@ char* format_birthdate(scfg_t* cfg, const char* birthdate, char* out, size_t max
return NULL;
*out = '\0';
if(*birthdate) {
if(cfg->sys_misc & SM_EURODATE)
if (cfg->sys_date_fmt == YYMMDD)
safe_snprintf(out, maxlen, "%04u/%02u/%02u"
, getbirthyear(birthdate), getbirthmonth(cfg, birthdate), getbirthday(cfg, birthdate));
else if (cfg->sys_date_fmt == DDMMYY)
safe_snprintf(out, maxlen, "%02u/%02u/%04u"
,getbirthday(cfg, birthdate), getbirthmonth(cfg, birthdate), getbirthyear(birthdate));
else
......@@ -1023,7 +1040,12 @@ char* format_birthdate(scfg_t* cfg, const char* birthdate, char* out, size_t max
const char* birthdate_format(scfg_t* cfg)
{
return cfg->sys_misc&SM_EURODATE ? "DD/MM/YYYY" : "MM/DD/YYYY";
switch (cfg->sys_date_fmt) {
case MMDDYY: return "MM/DD/YYYY";
case DDMMYY: return "DD/MM/YYYY";
case YYMMDD: return "YYYY/MM/DD";
}
return "??????????";
}
/****************************************************************************/
......
......@@ -65,6 +65,7 @@ DLLEXPORT int getbirthyear(const char* birthdate);
DLLEXPORT char* getbirthdstr(scfg_t*, const char* birthdate, char* buf, size_t);
DLLEXPORT char* getbirthmmddyy(scfg_t*, const char* birthdate, char* buf, size_t);
DLLEXPORT char* getbirthddmmyy(scfg_t*, const char* birthdate, char* buf, size_t);
DLLEXPORT char* getbirthyymmdd(scfg_t*, const char* birthdate, char* buf, size_t);
DLLEXPORT char* parse_birthdate(scfg_t*, const char* birthdate, char* out, size_t);
DLLEXPORT char* format_birthdate(scfg_t*, const char* birthdate, char* out, size_t);
DLLEXPORT const char* birthdate_format(scfg_t*);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment