diff --git a/CHANGES.txt b/CHANGES.txt index 751e91d357..b4eaf6358e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -43,6 +43,7 @@ * More fixes to the TokenAllocator (CASSANDRA-12990) * NoReplicationTokenAllocator should work with zero replication factor (CASSANDRA-12983) Merged from 3.0: + * Fix cqlsh COPY for dates before 1900 (CASSANDRA-13185) * Use keyspace replication settings on system.size_estimates table (CASSANDRA-9639) * Add vm.max_map_count StartupCheck (CASSANDRA-13008) * Obfuscate password in stress-graphs (CASSANDRA-12233) diff --git a/pylib/cqlshlib/formatting.py b/pylib/cqlshlib/formatting.py index daa65293f3..08665fd6c3 100644 --- a/pylib/cqlshlib/formatting.py +++ b/pylib/cqlshlib/formatting.py @@ -356,7 +356,15 @@ def strftime(time_format, seconds, microseconds=0, timezone=None): ret_dt = ret_dt.replace(tzinfo=UTC()) if timezone: ret_dt = ret_dt.astimezone(timezone) - return ret_dt.strftime(time_format) + try: + return ret_dt.strftime(time_format) + except ValueError: + # CASSANDRA-13185: if the date cannot be formatted as a string, return a string with the milliseconds + # since the epoch. cqlsh does the exact same thing for values below datetime.MINYEAR (1) or above + # datetime.MAXYEAR (9999). Some versions of strftime() also have problems for dates between MIN_YEAR and 1900. + # cqlsh COPY assumes milliseconds from the epoch if it fails to parse a datetime string, and so it is + # able to correctly import timestamps exported as milliseconds since the epoch. + return '%d' % (seconds * 1000.0) microseconds_regex = re.compile("(.*)(?:\.(\d{1,6}))(.*)")