From a893b66f85799e4379df2400aa7d908f8cf3fad1 Mon Sep 17 00:00:00 2001 From: "Rob Swindell (on Debian Linux)" <rob@synchro.net> Date: Mon, 28 Oct 2024 21:16:43 -0700 Subject: [PATCH] Add option to display short dates in verbal/unambiguous formats Although we've added (in SBBS v3.20) configurable numeric date input/display formats for the system, the output was still ambiguous for users (e.g. NN/NN/NN which could be interpretted a number of ways), so I've added an option to choose "verbal" short date formats to be displayed where possible instead. The same value separate from the numeric format (whatever the sysop chose) is used in the verbal date output, but since month name abbreviations are 3 characters, only one separator is used (to keep the output length fixed at 8 characters). The new "Verbal" short date display format is choosable in the SCFG wizard and via SCFG->System->Short Date Format. --- src/sbbs3/atcodes.cpp | 14 +++++++------- src/sbbs3/con_out.cpp | 3 +-- src/sbbs3/date_str.c | 27 +++++++++++++++++++++++++++ src/sbbs3/date_str.h | 1 + src/sbbs3/execmisc.cpp | 2 +- src/sbbs3/js_global.c | 2 +- src/sbbs3/js_system.c | 2 +- src/sbbs3/putnode.cpp | 4 ++-- src/sbbs3/readmsgs.cpp | 3 +-- src/sbbs3/sbbs.h | 2 +- src/sbbs3/scfg/scfg.c | 8 +++++++- src/sbbs3/scfg/scfg.h | 1 + src/sbbs3/scfg/scfgsys.c | 40 +++++++++++++++++++++++++++++++++++----- src/sbbs3/scfgdefs.h | 1 + src/sbbs3/scfglib1.c | 1 + src/sbbs3/scfgsave.c | 1 + src/sbbs3/str.cpp | 16 +++++++++------- src/sbbs3/upload.cpp | 2 +- src/sbbs3/useredit.cpp | 14 +++++++------- 19 files changed, 106 insertions(+), 38 deletions(-) diff --git a/src/sbbs3/atcodes.cpp b/src/sbbs3/atcodes.cpp index 86977bb6c5..e2cce3a4d1 100644 --- a/src/sbbs3/atcodes.cpp +++ b/src/sbbs3/atcodes.cpp @@ -758,7 +758,7 @@ const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode, return(smb_zonestr(sys_timezone(&cfg),str)); if(!strcmp(sp,"DATE") || !strcmp(sp,"SYSDATE")) { - return(unixtodstr(&cfg,time32(NULL),str)); + return datestr(time(NULL)); } if(strncmp(sp, "DATE:", 5) == 0 || strncmp(sp, "TIME:", 5) == 0) { @@ -1113,7 +1113,7 @@ const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode, } if(strcmp(sp, "PWDATE") == 0 || strcmp(sp, "MEMO") == 0) - return(unixtodstr(&cfg,useron.pwmod,str)); + return datestr(useron.pwmod); if(strncmp(sp, "PWDATE:", 7) == 0) { SAFECOPY(tmp, sp + 7); @@ -1131,7 +1131,7 @@ const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode, } if(!strcmp(sp,"SINCE")) - return(unixtodstr(&cfg,useron.firston,str)); + return datestr(useron.firston); if(strncmp(sp, "SINCE:", 6) == 0) { SAFECOPY(tmp, sp + 6); @@ -1205,7 +1205,7 @@ const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode, return(timestr(useron.laston)); if(!strcmp(sp,"LASTDATEON")) - return(unixtodstr(&cfg,useron.laston,str)); + return datestr(useron.laston); if(strncmp(sp, "LASTON:", 7) == 0) { SAFECOPY(tmp, sp + 7); @@ -1235,7 +1235,7 @@ const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode, return(timestr(useron.firston)); if(!strcmp(sp,"FIRSTDATEON")) - return(unixtodstr(&cfg,useron.firston,str)); + return datestr(useron.firston); if(strncmp(sp, "FIRSTON:", 8) == 0) { SAFECOPY(tmp, sp + 8); @@ -1413,7 +1413,7 @@ const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode, } if(!strcmp(sp,"LASTNEW")) - return(unixtodstr(&cfg,(time32_t)ns_time,str)); + return datestr(ns_time); if(strncmp(sp, "LASTNEW:", 8) == 0) { SAFECOPY(tmp, sp + 8); @@ -1483,7 +1483,7 @@ const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode, } if(!strcmp(sp,"EXDATE") || !strcmp(sp,"EXPDATE")) - return(unixtodstr(&cfg,useron.expire,str)); + return datestr(useron.expire); if(strncmp(sp, "EXPDATE:", 8) == 0) { if(!useron.expire) diff --git a/src/sbbs3/con_out.cpp b/src/sbbs3/con_out.cpp index e5349109c6..4f24833996 100644 --- a/src/sbbs3/con_out.cpp +++ b/src/sbbs3/con_out.cpp @@ -1121,7 +1121,6 @@ void sbbs_t::getdimensions() /****************************************************************************/ void sbbs_t::ctrl_a(char x) { - char tmp1[128]; uint atr = curatr; struct tm tm; @@ -1219,7 +1218,7 @@ void sbbs_t::ctrl_a(char x) break; case 'D': /* Date */ now=time(NULL); - bputs(unixtodstr(&cfg,(time32_t)now,tmp1)); + bputs(datestr(now)); break; case ',': /* Delay 1/10 sec */ mswait(100); diff --git a/src/sbbs3/date_str.c b/src/sbbs3/date_str.c index 2e0f82951a..db6a6830c6 100644 --- a/src/sbbs3/date_str.c +++ b/src/sbbs3/date_str.c @@ -148,6 +148,33 @@ char* unixtodstr(scfg_t* cfg, time32_t t, char *str) return str; } +/****************************************************************************/ +/****************************************************************************/ +char* datestr(scfg_t* cfg, time_t t, char* str) +{ + if(t == 0) + return "---------"; + if(!cfg->sys_date_verbal) + return unixtodstr(cfg, (time32_t)t, str); + struct tm tm = {}; + if(localtime_r(&t, &tm) == NULL) + return "!!!!!!!!!"; + char fmt[32] = ""; + switch(cfg->sys_date_fmt) { + case MMDDYY: + snprintf(fmt, sizeof fmt, "%%b%%d%c%%y", cfg->sys_date_sep); + break; + case DDMMYY: + snprintf(fmt, sizeof fmt, "%%d%c%%b%%y", cfg->sys_date_sep); + break; + case YYMMDD: + snprintf(fmt, sizeof fmt, "%%y%c%%b%%d", cfg->sys_date_sep); + break; + } + strftime(str, 9, fmt, &tm); + return str; +} + /****************************************************************************/ /* Takes the value 'sec' and makes a string the format HH:MM:SS */ /****************************************************************************/ diff --git a/src/sbbs3/date_str.h b/src/sbbs3/date_str.h index ad87b45b6d..3d070f2ce4 100644 --- a/src/sbbs3/date_str.h +++ b/src/sbbs3/date_str.h @@ -37,6 +37,7 @@ DLLEXPORT char * date_template(scfg_t*, char* buf, size_t); DLLEXPORT char * zonestr(short zone); DLLEXPORT time32_t dstrtounix(scfg_t*, const char *str); DLLEXPORT char * unixtodstr(scfg_t*, time32_t, char *str); +DLLEXPORT char * datestr(scfg_t*, time_t, char* str); DLLEXPORT char * sectostr(uint sec, char *str); DLLEXPORT char * seconds_to_str(uint, char*); DLLEXPORT char * hhmmtostr(scfg_t* cfg, struct tm* tm, char* str); diff --git a/src/sbbs3/execmisc.cpp b/src/sbbs3/execmisc.cpp index f7310cca19..7e1d0119cd 100644 --- a/src/sbbs3/execmisc.cpp +++ b/src/sbbs3/execmisc.cpp @@ -567,7 +567,7 @@ int sbbs_t::exec_misc(csi_t* csi, const char *path) lp=getintvar(csi,*(int32_t *)csi->ip); csi->ip+=4; /* Skip int variable name */ if(pp && lp) { - unixtodstr(&cfg,*lp,str); + datestr(*lp, str); *pp=copystrvar(csi,*pp,str); } return(0); diff --git a/src/sbbs3/js_global.c b/src/sbbs3/js_global.c index 3da1544433..a6a611de6d 100644 --- a/src/sbbs3/js_global.c +++ b/src/sbbs3/js_global.c @@ -2228,7 +2228,7 @@ js_html_encode(JSContext *cx, uintN argc, jsval *arglist) case 'D': now=time(NULL); - j+=sprintf(outbuf+j,"%s",unixtodstr(p->cfg,(time32_t)now,tmp1)); + j+=sprintf(outbuf+j,"%s",datestr(p->cfg,now,tmp1)); break; case 'T': now=time(NULL); diff --git a/src/sbbs3/js_system.c b/src/sbbs3/js_system.c index d0dadb5f3e..ab9eecb0fc 100644 --- a/src/sbbs3/js_system.c +++ b/src/sbbs3/js_system.c @@ -1292,7 +1292,7 @@ js_datestr(JSContext *cx, uintN argc, jsval *arglist) } JS_ValueToECMAUint32(cx,argv[0],(uint32_t*)&t); } - unixtodstr(sys->cfg,t,str); + datestr(sys->cfg,t,str); if((js_str = JS_NewStringCopyZ(cx, str))==NULL) return(JS_FALSE); diff --git a/src/sbbs3/putnode.cpp b/src/sbbs3/putnode.cpp index 1f905eba57..333dcea0a1 100644 --- a/src/sbbs3/putnode.cpp +++ b/src/sbbs3/putnode.cpp @@ -28,7 +28,7 @@ /****************************************************************************/ int sbbs_t::putnodedat(uint number, node_t* node) { - char str[256],firston[25]; + char str[256]; char path[MAX_PATH+1]; int wr=0; int wrerr=0; @@ -54,7 +54,7 @@ int sbbs_t::putnodedat(uint number, node_t* node) ,useron.sex ,useron.comp ,useron.ipaddr - ,unixtodstr(&cfg,useron.firston,firston) + ,datestr(useron.firston) ,node->aux&0xff ,node->connection ); diff --git a/src/sbbs3/readmsgs.cpp b/src/sbbs3/readmsgs.cpp index 7d3e6a7e8b..4a03eb1d04 100644 --- a/src/sbbs3/readmsgs.cpp +++ b/src/sbbs3/readmsgs.cpp @@ -343,7 +343,6 @@ static int find_post(smb_t* smb, uint32_t msgnum, post_t* post) void sbbs_t::show_thread(uint32_t msgnum, post_t* post, unsigned curmsg, int thread_depth, uint64_t reply_mask) { - char date[32]; smbmsg_t msg; int i = find_post(&smb, msgnum, post); @@ -373,7 +372,7 @@ void sbbs_t::show_thread(uint32_t msgnum, post_t* post, unsigned curmsg, int thr ? text[Anonymous] : msghdr_field(&msg, msg.from) ,(unsigned)i == curmsg ? '<' : ' ' ,msg_listing_flag(smb.subnum, &msg, &post[i]) - ,unixtodstr(&cfg, msg.hdr.when_written.time, date)); + ,datestr(msg.hdr.when_written.time)); if(thread_depth) { if(msg.hdr.thread_first) diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h index 85d2e26f4c..7266d7920a 100644 --- a/src/sbbs3/sbbs.h +++ b/src/sbbs3/sbbs.h @@ -822,7 +822,7 @@ public: void revert_text(void); char* server_host_name(void); char* timestr(time_t); - char* datestr(time_t); + char* datestr(time_t, char* str = nullptr); char timestr_output[60]{}; char datestr_output[60]{}; char* age_of_posted_item(char* buf, size_t max, time_t); diff --git a/src/sbbs3/scfg/scfg.c b/src/sbbs3/scfg/scfg.c index e409353647..7831e1398c 100644 --- a/src/sbbs3/scfg/scfg.c +++ b/src/sbbs3/scfg/scfg.c @@ -199,7 +199,7 @@ void cfg_wizard(void) } int stage = 0; - int total = 16; + int total = 17; scfg_t saved_cfg = cfg; do { switch(stage) { @@ -292,6 +292,12 @@ void cfg_wizard(void) continue; } break; + case __COUNTER__: + if(edit_sys_date_verbal(stage, total) < 0) { + --stage; + continue; + } + break; case __COUNTER__: if(edit_sys_newuser_policy(stage, total) < 0) { --stage; diff --git a/src/sbbs3/scfg/scfg.h b/src/sbbs3/scfg/scfg.h index d88894127b..bf45bcffd6 100644 --- a/src/sbbs3/scfg/scfg.h +++ b/src/sbbs3/scfg/scfg.h @@ -154,6 +154,7 @@ int edit_sys_inetaddr(int page, int total); int edit_sys_timezone(int page, int total); int edit_sys_timefmt(int page, int total); int edit_sys_datefmt(int page, int total); +int edit_sys_date_verbal(int page, int total); int edit_sys_newuser_policy(int page, int total); int edit_sys_alias_policy(int page, int total); int edit_sys_delmsg_policy(int page, int total); diff --git a/src/sbbs3/scfg/scfgsys.c b/src/sbbs3/scfg/scfgsys.c index 11877491f2..cbdb7d36f8 100644 --- a/src/sbbs3/scfg/scfgsys.c +++ b/src/sbbs3/scfg/scfgsys.c @@ -465,7 +465,7 @@ int edit_sys_newuser_policy(int page, int total) ; if(page) mode = wiz_help(page, total, uifc.helpbuf); - i=uifc.list(mode,0,10,0,&i,0 + i=uifc.list(mode,0,11,0,&i,0 ,"Open to New Users",uifcYesNoOpts); if(i == 0) { cfg.sys_misc &= ~SM_CLOSED; @@ -1329,7 +1329,7 @@ int edit_sys_datefmt(int page, int total) "MM DD YY", "DD MM YY", "YY MM DD", NULL }; uifc.helpbuf= - "`Date Display Format:`\n" + "`Numeric Date 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" @@ -1344,7 +1344,7 @@ int edit_sys_datefmt(int page, int total) uifc.list_height = 7; } i=uifc.list(mode, 0, 11, 0,&i,0 - ,"Date Display Format", opts); + ,"Numeric Date Format", opts); if (i < 0) return i; cfg.sys_date_fmt = i % 3; @@ -1359,6 +1359,32 @@ int edit_sys_datefmt(int page, int total) return i; } +int edit_sys_date_verbal(int page, int total) +{ + int mode = WIN_SAV | WIN_MID; + int i = cfg.sys_date_verbal; + char* opts[] = { + "Numeric", "Verbal", + NULL }; + uifc.helpbuf= + "`Short Date Display Format:`\n" + "\n" + "If you would like abbreviated dates to be displayed using verbal\n" + "(non-numeric, unambiguous) month name abbreviations, choose `Verbal`."; + ; + if(page) { + mode = wiz_help(page, total, uifc.helpbuf); + mode |= WIN_FIXEDHEIGHT; + uifc.list_height = 2; + } + i=uifc.list(mode, 0, 11, 0,&i,0 + ,"Short Date Display Format", opts); + if (i < 0) + return i; + cfg.sys_date_verbal = i; + return i; +} + int edit_sys_alias_policy(int page, int total) { int mode = WIN_SAV | WIN_MID; @@ -1669,6 +1695,7 @@ void sys_cfg(void) static int uq_cur, uq_bar; static int newtog_cur, newtog_bar; char str[81],done=0; + char dstr[9]; int i,j; scfg_t saved_cfg = cfg; char sys_pass[sizeof(cfg.sys_pass)]; @@ -1680,7 +1707,9 @@ 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, str, sizeof str)); + snprintf(opt[i++],MAX_OPLN,"%-20s%s (e.g. %s)","Short Date Format" + ,date_format(&cfg, str, sizeof str) + ,datestr(&cfg, time(NULL), dstr)); snprintf(opt[i++],MAX_OPLN,"%-20s%s","Operator",cfg.sys_op); strcpy(opt[i++],"Notifications..."); @@ -1723,7 +1752,8 @@ void sys_cfg(void) edit_sys_timezone(false, false); break; case 3: - edit_sys_datefmt(false, false); + if(edit_sys_datefmt(false, false) >= 0) + edit_sys_date_verbal(false, false); break; case 4: edit_sys_operator(false, false); diff --git a/src/sbbs3/scfgdefs.h b/src/sbbs3/scfgdefs.h index 0f7e90da3b..2f7316078a 100644 --- a/src/sbbs3/scfgdefs.h +++ b/src/sbbs3/scfgdefs.h @@ -464,6 +464,7 @@ typedef struct int16_t sys_timezone; /* Time Zone of BBS */ enum date_fmt sys_date_fmt; char sys_date_sep; + bool sys_date_verbal; char sys_daily[LEN_CMD+1]; /* Daily event */ char sys_logon[LEN_CMD+1]; /* Logon event */ char sys_logout[LEN_CMD+1]; /* Logoff event */ diff --git a/src/sbbs3/scfglib1.c b/src/sbbs3/scfglib1.c index 90f724f6f1..56ca69705c 100644 --- a/src/sbbs3/scfglib1.c +++ b/src/sbbs3/scfglib1.c @@ -104,6 +104,7 @@ bool read_main_cfg(scfg_t* cfg, char* error, size_t maxerrlen) 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_date_sep = *iniGetString(ini, NULL, "date_sep", "/", value); + cfg->sys_date_verbal = iniGetBool(ini, NULL, "date_verbal", false); 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); diff --git a/src/sbbs3/scfgsave.c b/src/sbbs3/scfgsave.c index 1541e7e482..8830a92816 100644 --- a/src/sbbs3/scfgsave.c +++ b/src/sbbs3/scfgsave.c @@ -125,6 +125,7 @@ bool write_main_cfg(scfg_t* cfg) iniSetUInteger(&ini, ROOT_SECTION, "date_fmt", cfg->sys_date_fmt, NULL); SAFEPRINTF(tmp, "%c", cfg->sys_date_sep); iniSetString(&ini, ROOT_SECTION, "date_sep", tmp, NULL); + iniSetBool(&ini, ROOT_SECTION, "date_verbal", cfg->sys_date_verbal, 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); diff --git a/src/sbbs3/str.cpp b/src/sbbs3/str.cpp index be469aad49..b690d61313 100644 --- a/src/sbbs3/str.cpp +++ b/src/sbbs3/str.cpp @@ -217,14 +217,14 @@ void sbbs_t::userlist(int mode) sprintf(name,"%s #%d",user.alias,i); sprintf(line[j],text[UserListFmt],name ,cfg.sys_misc&SM_LISTLOC ? user.location : user.note - ,unixtodstr(&cfg,user.laston,tmp) + ,datestr(user.laston,tmp) ,user.modem); } else { sprintf(name,"%s #%u",user.alias,i); bprintf(text[UserListFmt],name ,cfg.sys_misc&SM_LISTLOC ? user.location : user.note - ,unixtodstr(&cfg,user.laston,tmp) + ,datestr(user.laston,tmp) ,user.modem); } j++; @@ -976,9 +976,11 @@ char* sbbs_t::timestr(time_t intime) return(::timestr(&cfg,(time32_t)intime,timestr_output)); } -char* sbbs_t::datestr(time_t t) +char* sbbs_t::datestr(time_t t, char* str) { - return unixtodstr(&cfg, (time32_t)t, datestr_output); + if(str == nullptr) + str = datestr_output; + return ::datestr(&cfg, t, str); } void sbbs_t::sys_info() @@ -1030,9 +1032,9 @@ void sbbs_t::user_info() if(localtime32(&useron.laston,&tm)!=NULL) bprintf(text[UserDates] - ,unixtodstr(&cfg,useron.firston,str) - ,unixtodstr(&cfg,useron.expire,tmp) - ,unixtodstr(&cfg,useron.laston,tmp2) + ,datestr(useron.firston,str) + ,datestr(useron.expire,tmp) + ,datestr(useron.laston,tmp2) ,tm.tm_hour,tm.tm_min); bprintf(text[UserTimes] diff --git a/src/sbbs3/upload.cpp b/src/sbbs3/upload.cpp index 00034462de..3a4ca228e4 100644 --- a/src/sbbs3/upload.cpp +++ b/src/sbbs3/upload.cpp @@ -358,7 +358,7 @@ bool sbbs_t::upload(int dirnum, const char* fname) now=time(NULL); if(descbeg[0]) strcat(descbeg," "); - SAFEPRINTF(str,"%s ",unixtodstr(&cfg,(time32_t)now,tmp)); + SAFEPRINTF(str,"%s ",datestr(now,tmp)); strcat(descbeg,str); } if(cfg.dir[dirnum]->misc&DIR_MULT) { diff --git a/src/sbbs3/useredit.cpp b/src/sbbs3/useredit.cpp index 4f1db5534d..fbd368b009 100644 --- a/src/sbbs3/useredit.cpp +++ b/src/sbbs3/useredit.cpp @@ -87,7 +87,7 @@ void sbbs_t::useredit(int usernumber) SAFEPRINTF2(user_pass, "%.*s..", (int)(max_len - 2), user.pass); bprintf(text[UeditAliasPassword] ,user.alias - ,unixtodstr(&cfg,user.pwmod,tmp) + ,datestr(user.pwmod,tmp) ,(user.level>useron.level || !(cfg.sys_misc&SM_ECHO_PW)) ? "<hidden>" : user_pass ); bprintf(text[UeditRealNamePhone] @@ -115,8 +115,8 @@ void sbbs_t::useredit(int usernumber) if(localtime32(&user.laston,&tm)==NULL) return; bprintf(text[UserDates] - ,unixtodstr(&cfg,user.firston,str),unixtodstr(&cfg,user.expire,tmp) - ,unixtodstr(&cfg,user.laston,tmp2),tm.tm_hour, tm.tm_min); + ,datestr(user.firston,str),datestr(user.expire,tmp) + ,datestr(user.laston,tmp2),tm.tm_hour, tm.tm_min); bprintf(text[UserTimes] ,user.timeon,user.ttoday,cfg.level_timeperday[user.level] @@ -341,28 +341,28 @@ void sbbs_t::useredit(int usernumber) break; case 'K': /* date changes */ bputs(text[UeditLastOn]); - unixtodstr(&cfg,user.laston,str); + datestr(user.laston,str); gettmplt(str, date_template(&cfg, tmp, sizeof tmp),K_LINE|K_EDIT); if(sys_status&SS_ABORT) break; user.laston=dstrtounix(&cfg,str); putuserdatetime(user.number, USER_LASTON, user.laston); bputs(text[UeditFirstOn]); - unixtodstr(&cfg,user.firston,str); + datestr(user.firston,str); gettmplt(str, date_template(&cfg, tmp, sizeof tmp),K_LINE|K_EDIT); if(sys_status&SS_ABORT) break; user.firston=dstrtounix(&cfg,str); putuserdatetime(user.number, USER_FIRSTON, user.firston); bputs(text[UeditExpire]); - unixtodstr(&cfg,user.expire,str); + datestr(user.expire,str); gettmplt(str, date_template(&cfg, tmp, sizeof tmp),K_LINE|K_EDIT); if(sys_status&SS_ABORT) break; user.expire=dstrtounix(&cfg,str); putuserdatetime(user.number, USER_EXPIRE, user.expire); bputs(text[UeditPwModDate]); - unixtodstr(&cfg,user.pwmod,str); + datestr(user.pwmod,str); gettmplt(str, date_template(&cfg, tmp, sizeof tmp),K_LINE|K_EDIT); if(sys_status&SS_ABORT) break; -- GitLab