1
0
forked from aniani/vim

patch 8.1.2326: cannot parse a date/time string

Problem:    Cannot parse a date/time string.
Solution:   Add strptime(). (Stephen Wall, closes #)
This commit is contained in:
Bram Moolenaar
2019-11-21 15:36:18 +01:00
parent 9ae862ebba
commit 10455d43fe
9 changed files with 121 additions and 20 deletions

View File

@@ -1,4 +1,4 @@
*eval.txt* For Vim version 8.1. Last change: 2019 Nov 17 *eval.txt* For Vim version 8.1. Last change: 2019 Nov 21
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -488,7 +488,7 @@ as a key.
To avoid having to put quotes around every key the #{} form can be used. This To avoid having to put quotes around every key the #{} form can be used. This
does require the key to consist only of ASCII letters, digits, '-' and '_'. does require the key to consist only of ASCII letters, digits, '-' and '_'.
Example: > Example: >
let mydict = #{zero: 0, one_key: 1, two-key: 2, 333: 3} :let mydict = #{zero: 0, one_key: 1, two-key: 2, 333: 3}
Note that 333 here is the string "333". Empty keys are not possible with #{}. Note that 333 here is the string "333". Empty keys are not possible with #{}.
A value can be any expression. Using a Dictionary for a value creates a A value can be any expression. Using a Dictionary for a value creates a
@@ -2667,7 +2667,7 @@ remote_read({serverid} [, {timeout}])
remote_send({server}, {string} [, {idvar}]) remote_send({server}, {string} [, {idvar}])
String send key sequence String send key sequence
remote_startserver({name}) none become server {name} remote_startserver({name}) none become server {name}
remove({list}, {idx} [, {end}]) any/List remove({list}, {idx} [, {end}]) any/List
remove items {idx}-{end} from {list} remove items {idx}-{end} from {list}
remove({blob}, {idx} [, {end}]) Number/Blob remove({blob}, {idx} [, {end}]) Number/Blob
remove bytes {idx}-{end} from {blob} remove bytes {idx}-{end} from {blob}
@@ -2770,7 +2770,7 @@ strchars({expr} [, {skipcc}]) Number character length of the String {expr}
strcharpart({str}, {start} [, {len}]) strcharpart({str}, {start} [, {len}])
String {len} characters of {str} at {start} String {len} characters of {str} at {start}
strdisplaywidth({expr} [, {col}]) Number display length of the String {expr} strdisplaywidth({expr} [, {col}]) Number display length of the String {expr}
strftime({format} [, {time}]) String time in specified format strftime({format} [, {time}]) String format time with a specified format
strgetchar({str}, {index}) Number get char {index} from {str} strgetchar({str}, {index}) Number get char {index} from {str}
stridx({haystack}, {needle} [, {start}]) stridx({haystack}, {needle} [, {start}])
Number index of {needle} in {haystack} Number index of {needle} in {haystack}
@@ -2778,6 +2778,8 @@ string({expr}) String String representation of {expr} value
strlen({expr}) Number length of the String {expr} strlen({expr}) Number length of the String {expr}
strpart({str}, {start} [, {len}]) strpart({str}, {start} [, {len}])
String {len} characters of {str} at {start} String {len} characters of {str} at {start}
strptime({format}, {timestring})
Number Convert {timestring} to unix timestamp
strridx({haystack}, {needle} [, {start}]) strridx({haystack}, {needle} [, {start}])
Number last index of {needle} in {haystack} Number last index of {needle} in {haystack}
strtrans({expr}) String translate string to make it printable strtrans({expr}) String translate string to make it printable
@@ -5634,7 +5636,7 @@ getwininfo([{winid}]) *getwininfo()*
terminal 1 if a terminal window terminal 1 if a terminal window
{only with the +terminal feature} {only with the +terminal feature}
tabnr tab page number tabnr tab page number
topline first displayed buffer line topline first displayed buffer line
variables a reference to the dictionary with variables a reference to the dictionary with
window-local variables window-local variables
width window width width window width
@@ -5652,7 +5654,7 @@ getwininfo([{winid}]) *getwininfo()*
getwinpos([{timeout}]) *getwinpos()* getwinpos([{timeout}]) *getwinpos()*
The result is a list with two numbers, the result of The result is a list with two numbers, the result of
getwinposx() and getwinposy() combined: |getwinposx()| and |getwinposy()| combined:
[x-pos, y-pos] [x-pos, y-pos]
{timeout} can be used to specify how long to wait in msec for {timeout} can be used to specify how long to wait in msec for
a response from the terminal. When omitted 100 msec is used. a response from the terminal. When omitted 100 msec is used.
@@ -6614,7 +6616,7 @@ listener_remove({id}) *listener_remove()*
localtime() *localtime()* localtime() *localtime()*
Return the current time, measured as seconds since 1st Jan Return the current time, measured as seconds since 1st Jan
1970. See also |strftime()| and |getftime()|. 1970. See also |strftime()|, |strptime()| and |getftime()|.
log({expr}) *log()* log({expr}) *log()*
@@ -7103,9 +7105,9 @@ mkdir({name} [, {path} [, {prot}]])
There is no error if the directory already exists and the "p" There is no error if the directory already exists and the "p"
flag is passed (since patch 8.0.1708). However, without the flag is passed (since patch 8.0.1708). However, without the
"p" option the call will fail. "p" option the call will fail.
The function result is a Number, which is 1 if the call was The function result is a Number, which is 1 if the call was
successful or 0 if the directory creation failed or partly successful or 0 if the directory creation failed or partly
failed. failed.
@@ -9267,7 +9269,7 @@ strftime({format} [, {time}]) *strftime()*
{format} depends on your system, thus this is not portable! {format} depends on your system, thus this is not portable!
See the manual page of the C function strftime() for the See the manual page of the C function strftime() for the
format. The maximum length of the result is 80 characters. format. The maximum length of the result is 80 characters.
See also |localtime()| and |getftime()|. See also |localtime()|, |getftime()| and |strptime()|.
The language can be changed with the |:language| command. The language can be changed with the |:language| command.
Examples: > Examples: >
:echo strftime("%c") Sun Apr 27 11:49:23 1997 :echo strftime("%c") Sun Apr 27 11:49:23 1997
@@ -9368,6 +9370,34 @@ strpart({src}, {start} [, {len}]) *strpart()*
Can also be used as a |method|: > Can also be used as a |method|: >
GetText()->strpart(5) GetText()->strpart(5)
strptime({format}, {timestring}) *strptime()*
The result is a Number, which is a unix timestamp representing
the date and time in {timestring}, which is expected to match
the format specified in {format}.
The accepted {format} depends on your system, thus this is not
portable! See the manual page of the C function strptime()
for the format. Especially avoid "%c". The value of $TZ also
matters.
If the {timestring} cannot be parsed with {format} zero is
returned. If you do not know the format of {timestring} you
can try different {format} values until you get a non-zero
result.
See also |strftime()|.
Examples: >
:echo strptime("%Y %b %d %X", "1997 Apr 27 11:49:23")
< 862156163 >
:echo strftime("%c", strptime("%y%m%d %T", "970427 11:53:55"))
< Sun Apr 27 11:53:55 1997 >
:echo strftime("%c", strptime("%Y%m%d%H%M%S", "19970427115355") + 3600)
< Sun Apr 27 12:53:55 1997
Not available on all systems. To check use: >
:if exists("*strptime")
strridx({haystack}, {needle} [, {start}]) *strridx()* strridx({haystack}, {needle} [, {start}]) *strridx()*
The result is a Number, which gives the byte index in The result is a Number, which gives the byte index in
{haystack} of the last occurrence of the String {needle}. {haystack} of the last occurrence of the String {needle}.

View File

@@ -796,6 +796,7 @@ Date and Time: *date-functions* *time-functions*
getftime() get last modification time of a file getftime() get last modification time of a file
localtime() get current time in seconds localtime() get current time in seconds
strftime() convert time to a string strftime() convert time to a string
strptime() convert a date/time string to time
reltime() get the current or elapsed time accurately reltime() get the current or elapsed time accurately
reltimestr() convert reltime() result to a string reltimestr() convert reltime() result to a string
reltimefloat() convert reltime() result to a Float reltimefloat() convert reltime() result to a Float

4
src/auto/configure vendored
View File

@@ -12572,8 +12572,8 @@ for ac_func in fchdir fchown fchmod fsync getcwd getpseudotty \
memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \ memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \
getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \ getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \
sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \ sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \
strnicmp strpbrk strtol tgetent towlower towupper iswupper tzset \ strnicmp strpbrk strptime strtol tgetent towlower towupper iswupper \
usleep utime utimes mblen ftruncate unsetenv posix_openpt tzset usleep utime utimes mblen ftruncate unsetenv posix_openpt
do : do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"

View File

@@ -206,6 +206,7 @@
#undef HAVE_STRNCASECMP #undef HAVE_STRNCASECMP
#undef HAVE_STRNICMP #undef HAVE_STRNICMP
#undef HAVE_STRPBRK #undef HAVE_STRPBRK
#undef HAVE_STRPTIME
#undef HAVE_STRTOL #undef HAVE_STRTOL
#undef HAVE_CANBERRA #undef HAVE_CANBERRA
#undef HAVE_ST_BLKSIZE #undef HAVE_ST_BLKSIZE

View File

@@ -3744,8 +3744,8 @@ AC_CHECK_FUNCS(fchdir fchown fchmod fsync getcwd getpseudotty \
memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \ memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \
getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \ getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \
sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \ sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \
strnicmp strpbrk strtol tgetent towlower towupper iswupper tzset \ strnicmp strpbrk strptime strtol tgetent towlower towupper iswupper \
usleep utime utimes mblen ftruncate unsetenv posix_openpt) tzset usleep utime utimes mblen ftruncate unsetenv posix_openpt)
AC_FUNC_SELECT_ARGTYPES AC_FUNC_SELECT_ARGTYPES
AC_FUNC_FSEEKO AC_FUNC_FSEEKO

View File

@@ -20,7 +20,7 @@
# include <float.h> # include <float.h>
#endif #endif
#ifdef MACOS_X #if defined(MACOS_X)
# include <time.h> // for time_t # include <time.h> // for time_t
#endif #endif
@@ -237,6 +237,9 @@ static void f_stridx(typval_T *argvars, typval_T *rettv);
static void f_strlen(typval_T *argvars, typval_T *rettv); static void f_strlen(typval_T *argvars, typval_T *rettv);
static void f_strcharpart(typval_T *argvars, typval_T *rettv); static void f_strcharpart(typval_T *argvars, typval_T *rettv);
static void f_strpart(typval_T *argvars, typval_T *rettv); static void f_strpart(typval_T *argvars, typval_T *rettv);
#ifdef HAVE_STRPTIME
static void f_strptime(typval_T *argvars, typval_T *rettv);
#endif
static void f_strridx(typval_T *argvars, typval_T *rettv); static void f_strridx(typval_T *argvars, typval_T *rettv);
static void f_strtrans(typval_T *argvars, typval_T *rettv); static void f_strtrans(typval_T *argvars, typval_T *rettv);
static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv); static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
@@ -738,6 +741,9 @@ static funcentry_T global_functions[] =
{"string", 1, 1, FEARG_1, f_string}, {"string", 1, 1, FEARG_1, f_string},
{"strlen", 1, 1, FEARG_1, f_strlen}, {"strlen", 1, 1, FEARG_1, f_strlen},
{"strpart", 2, 3, FEARG_1, f_strpart}, {"strpart", 2, 3, FEARG_1, f_strpart},
#ifdef HAVE_STRPTIME
{"strptime", 2, 2, FEARG_1, f_strptime},
#endif
{"strridx", 2, 3, FEARG_1, f_strridx}, {"strridx", 2, 3, FEARG_1, f_strridx},
{"strtrans", 1, 1, FEARG_1, f_strtrans}, {"strtrans", 1, 1, FEARG_1, f_strtrans},
{"strwidth", 1, 1, FEARG_1, f_strwidth}, {"strwidth", 1, 1, FEARG_1, f_strwidth},
@@ -7412,6 +7418,40 @@ f_strpart(typval_T *argvars, typval_T *rettv)
rettv->vval.v_string = vim_strnsave(p + n, len); rettv->vval.v_string = vim_strnsave(p + n, len);
} }
#ifdef HAVE_STRPTIME
/*
* "strptime({format}, {timestring})" function
*/
static void
f_strptime(typval_T *argvars, typval_T *rettv)
{
struct tm tmval;
char_u *fmt;
char_u *str;
vimconv_T conv;
char_u *enc;
vim_memset(&tmval, NUL, sizeof(tmval));
fmt = tv_get_string(&argvars[0]);
str = tv_get_string(&argvars[1]);
conv.vc_type = CONV_NONE;
enc = enc_locale();
convert_setup(&conv, p_enc, enc);
if (conv.vc_type != CONV_NONE)
fmt = string_convert(&conv, fmt, NULL);
if (fmt == NULL
|| strptime((char *)str, (char *)fmt, &tmval) == NULL
|| (rettv->vval.v_number = mktime(&tmval)) == -1)
rettv->vval.v_number = 0;
if (conv.vc_type != CONV_NONE)
vim_free(fmt);
convert_setup(&conv, NULL, NULL);
vim_free(enc);
}
#endif
/* /*
* "strridx()" function * "strridx()" function
*/ */

View File

@@ -127,9 +127,16 @@
# endif # endif
#endif #endif
// on some systems time.h should not be included together with sys/time.h
#if !defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME) #if !defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME)
# include <time.h> /* on some systems time.h should not be // Needed for strptime()
included together with sys/time.h */ # ifndef _XOPEN_SOURCE
# define _XOPEN_SOURCE
# endif
# ifndef __USE_XOPEN
# define __USE_XOPEN
# endif
# include <time.h>
#endif #endif
#ifdef HAVE_SYS_TIME_H #ifdef HAVE_SYS_TIME_H
# include <sys/time.h> # include <sys/time.h>

View File

@@ -181,9 +181,8 @@ func Test_str2nr()
endfunc endfunc
func Test_strftime() func Test_strftime()
if !exists('*strftime') CheckFunction strftime
return
endif
" Format of strftime() depends on system. We assume " Format of strftime() depends on system. We assume
" that basic formats tested here are available and " that basic formats tested here are available and
" identical on all systems which support strftime(). " identical on all systems which support strftime().
@@ -222,7 +221,28 @@ func Test_strftime()
else else
unlet $TZ unlet $TZ
endif endif
endfunc
func Test_strptime()
CheckFunction strptime
if exists('$TZ')
let tz = $TZ
endif
let $TZ = 'UTC'
call assert_equal(1484653763, strptime('%Y-%m-%d %X', '2017-01-17 11:49:23'))
call assert_fails('call strptime()', 'E119:')
call assert_fails('call strptime("xxx")', 'E119:')
call assert_equal(0, strptime("%Y", ''))
call assert_equal(0, strptime("%Y", "xxx"))
if exists('tz')
let $TZ = tz
else
unlet $TZ
endif
endfunc endfunc
func Test_resolve_unix() func Test_resolve_unix()

View File

@@ -741,6 +741,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2326,
/**/ /**/
2325, 2325,
/**/ /**/