The simplest way would be to use slicing to just chop off the last three digits of the microseconds:
def format_time():
t = datetime.datetime.now()
s = t.strftime('%Y-%m-%d %H:%M:%S.%f')
return s[:-3]
I strongly recommend just chopping. I once wrote some logging code that rounded the timestamps rather than chopping, and I found it actually kind of confusing when the rounding changed the last digit. There was timed code that stopped running at a certain timestamp yet there were log events with that timestamp due to the rounding. Simpler and more predictable to just chop.
If you want to actually round the number rather than just chopping, it's a little more work but not horrible:
def format_time():
t = datetime.datetime.now()
s = t.strftime('%Y-%m-%d %H:%M:%S.%f')
head = s[:-7] # everything up to the '.'
tail = s[-7:] # the '.' and the 6 digits after it
f = float(tail)
temp = "{:.03f}".format(f) # for Python 2.x: temp = "%.3f" % f
new_tail = temp[1:] # temp[0] is always '0'; get rid of it
return head + new_tail
Obviously you can simplify the above with fewer variables; I just wanted it to be very easy to follow.
Answer from steveha on Stack OverflowThe simplest way would be to use slicing to just chop off the last three digits of the microseconds:
def format_time():
t = datetime.datetime.now()
s = t.strftime('%Y-%m-%d %H:%M:%S.%f')
return s[:-3]
I strongly recommend just chopping. I once wrote some logging code that rounded the timestamps rather than chopping, and I found it actually kind of confusing when the rounding changed the last digit. There was timed code that stopped running at a certain timestamp yet there were log events with that timestamp due to the rounding. Simpler and more predictable to just chop.
If you want to actually round the number rather than just chopping, it's a little more work but not horrible:
def format_time():
t = datetime.datetime.now()
s = t.strftime('%Y-%m-%d %H:%M:%S.%f')
head = s[:-7] # everything up to the '.'
tail = s[-7:] # the '.' and the 6 digits after it
f = float(tail)
temp = "{:.03f}".format(f) # for Python 2.x: temp = "%.3f" % f
new_tail = temp[1:] # temp[0] is always '0'; get rid of it
return head + new_tail
Obviously you can simplify the above with fewer variables; I just wanted it to be very easy to follow.
As of Python 3.6 the language has this feature built in:
def format_time():
t = datetime.datetime.now()
s = t.isoformat(timespec='milliseconds')
return s
To get a date string with milliseconds, use [:-3] to trim the last three digits of %f (microseconds):
>>> from datetime import datetime
>>> datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
'2022-09-24 10:18:32.926'
Or shorter:
>>> from datetime import datetime
>>> datetime.utcnow().strftime('%F %T.%f')[:-3]
'2022-09-24 10:18:32.926'
See the Python docs for more "%" format codes and the strftime(3) man page for the full list.
With Python 3.6+, you can set isoformat's timespec:
>>> from datetime import datetime
>>> datetime.utcnow().isoformat(sep=' ', timespec='milliseconds')
'2019-05-10 09:08:53.155'
Python 2.6 added a new strftime/strptime macro %f. The docs are a bit misleading as they only mention microseconds, but %f actually parses any decimal fraction of seconds with up to 6 digits, meaning it also works for milliseconds or even centiseconds or deciseconds.
time.strptime('30/03/09 16:31:32.123', '%d/%m/%y %H:%M:%S.%f')
However, time.struct_time doesn't actually store milliseconds/microseconds. You're better off using datetime, like this:
>>> from datetime import datetime
>>> a = datetime.strptime('30/03/09 16:31:32.123', '%d/%m/%y %H:%M:%S.%f')
>>> a.microsecond
123000
As you can see, .123 is correctly interpreted as 123 000 microseconds.
I know this is an older question but I'm still using Python 2.4.3 and I needed to find a better way of converting the string of data to a datetime.
The solution if datetime doesn't support %f and without needing a try/except is:
(dt, mSecs) = row[5].strip().split(".")
dt = datetime.datetime(*time.strptime(dt, "%Y-%m-%d %H:%M:%S")[0:6])
mSeconds = datetime.timedelta(microseconds = int(mSecs))
fullDateTime = dt + mSeconds
This works for the input string "2010-10-06 09:42:52.266000"
Function strptime() in not part of any Standard C library. It is well defined in *nix systems. It commonly uses a pointer to struct tm.
struct tm is defined to have at least 9 members. It may have more. There is no specified member corresponding to time units finer than seconds.
Sometimes struct tm has a member for milliseconds, microseconds, etc. Yet that is implementation dependent.
Referenced strptime() simply does not have a specifier for sub-seconds. Code needs to handle such optional members in some other fashion.
struct tm woes
Without "%Z", strptime() forms the struct tm without adjusting .tm_isdst. In general, strptime() does not certainly assign all struct tm members.
Initialize struct tm prior to the strptime().
struct tm time_stamp = { 0 };
Sample validation:
// Return error flag
bool testit(struct tm *t, int *ms, const char *date) {
memset(t, 0, sizeof *t);
const char *s = strptime(date, "%Y/%m/%dT%H:%M:%S", &t);
if (s == NULL) {
return true;
}
int n = 0;
sscanf(s, ".%3dZ%n", ms, &n);
return (n < 5 || s[5] != 0);
}
For the pedantic: detect rump milliseconds as exactly as 3 digits.
unsigned char *uc = (unsigned char *)s;
if (uc[0] != '.' || !isdigit(uc[1]) || !isdigit(uc[2])
|| !isdigit(uc[3]) || uc[4] != 'Z' || uc[5]) {
return true;
}
uc[4] = 0;
*ms = atoi(s + 1);
return false;
A workaround way is to design your own struct tm which contains a member for milliseconds:
struct tm2 {
struct tm tm;
long ms;
};
Then you have to parse the milliseconds part manually (I haved updated the code according to @Fe2O3's comment):
const char *date = "2023/10/04T11:41:03.553Z";
struct tm2 tm2;
char *peroid = strptime(date, "%Y/%m/%dT%H:%M:%S", &tm2.tm);
if (peroid == NULL) {
printf("error format!\n");
} else if (*peroid == '.') {
char *endstr;
tm2.ms = strtol(peroid + 1, &endstr, 10);
if (*endstr != 'Z') {
printf("error format!\n");
}
} else {
printf("error format!\n");
}
To make the code more robust, you can adjust error checking code.