I'm 开发者_运维百科trying to port an application from C# to Python. The application allows the user to choose their datetime format using C# String.Format DateTime formatting. Python's datetime formatting is not even close to the same, so I'm having to jump my code through a few hoops.
Is there any way Python can parse strings like yyyy-MM-dd HH-mm-ss
instead of %Y-%m-%d %H-%M-%S
?
You can get a fair distance by using simple replacement to convert the format strings.
_format_changes = (
('MMMM', '%B'),
('MMM', '%b'), # note: the order in this list is critical
('MM', '%m'),
('M', '%m'), # note: no exact equivalent
# etc etc
)
def conv_format(s):
for c, p in _format_changes:
# s.replace(c, p) #### typo/braino
s = s.replace(c, p)
return s
I presume that your "hoops" means something similar. Note that there are complications:
(1) the C# format can have literal text enclosed in single quotes (examples in the link you quoted)
(2) it probably allows a single character to be made a literal by escaping it with (e.g.) \
(3) The 12- or 24-hour clock stuff may need extra work (I haven't delved into the C# spec; this comment is based another similar exercise that I've been involved in).
You can end up writing a compiler and a byte-code interpreter to get around all the gotchas (like M, F, FF, FFF, ...).
An alternative to look at is using ctypes
or something similar to call the C#
RTL directly.
Update The original code was overly simplistic and had a typo/braino. The following new code shows how to address some of the issues (like literal text, and ensuring that a literal %
in the input doesn't make strftime unhappy). It doesn't attempt to give accurate answers where there's no direct conversion (M, F, etc). Places where an Exception could be raised are noted but the code operates on a laissez-faire basis.
_format_changes = (
('yyyy', '%Y'), ('yyy', '%Y'), ('yy', '%y'),('y', '%y'),
('MMMM', '%B'), ('MMM', '%b'), ('MM', '%m'),('M', '%m'),
('dddd', '%A'), ('ddd', '%a'), ('dd', '%d'),('d', '%d'),
('HH', '%H'), ('H', '%H'), ('hh', '%I'), ('h', '%I'),
('mm', '%M'), ('m', '%M'),
('ss', '%S'), ('s', '%S'),
('tt', '%p'), ('t', '%p'),
('zzz', '%z'), ('zz', '%z'), ('z', '%z'),
)
def cnv_csharp_date_fmt(in_fmt):
ofmt = ""
fmt = in_fmt
while fmt:
if fmt[0] == "'":
# literal text enclosed in ''
apos = fmt.find("'", 1)
if apos == -1:
# Input format is broken.
apos = len(fmt)
ofmt += fmt[1:apos].replace("%", "%%")
fmt = fmt[apos+1:]
elif fmt[0] == "\\":
# One escaped literal character.
# Note graceful behaviour when \ is the last character.
ofmt += fmt[1:2].replace("%", "%%")
fmt = fmt[2:]
else:
# This loop could be done with a regex "(yyyy)|(yyy)|etc".
for intok, outtok in _format_changes:
if fmt.startswith(intok):
ofmt += outtok
fmt = fmt[len(intok):]
break
else:
# Hmmmm, what does C# do here?
# What do *you* want to do here?
# I'll just emit one character as literal text
# and carry on. Alternative: raise an exception.
ofmt += fmt[0].replace("%", "%%")
fmt = fmt[1:]
return ofmt
Tested to the following extent:
>>> from cnv_csharp_date_fmt import cnv_csharp_date_fmt as cv
>>> cv("yyyy-MM-dd hh:mm:ss")
'%Y-%m-%d %I:%M:%S'
>>> cv("3pcts %%% yyyy-MM-dd hh:mm:ss")
'3pc%p%S %%%%%% %Y-%m-%d %I:%M:%S'
>>> cv("'3pcts' %%% yyyy-MM-dd hh:mm:ss")
'3pcts %%%%%% %Y-%m-%d %I:%M:%S'
>>> cv(r"3pc\t\s %%% yyyy-MM-dd hh:mm:ss")
'3pcts %%%%%% %Y-%m-%d %I:%M:%S'
>>>
Just run a few replaces first:
replacelist = [["yyyy","%Y"], ["MM","%m"]] # Etc etc
for replacer in replacelist:
string.replace(replacer[0],replacer[1])
In addition to the selected answer, this is for anyone that would want the same but in c# where formats are converted from python (Convert python datetime format to C# convert-able datetime format ), below is an extension that would do the job
public static string PythonToCSharpDateFormat(this string dateFormat)
{
string[][] changes = new string[][]
{
new string[]{"yyyy", "%Y"},new string[] {"yyy", "%Y"}, new string[]{"yy", "%y"},
new string[]{"y", "%y"}, new string[]{"MMMM", "%B"}, new string[]{"MMM", "%b"},
new string[]{"MM", "%m"}, new string[]{"M", "%m"}, new string[]{"dddd", "%A"},
new string[]{"ddd", "%a"}, new string[]{"dd", "%d"}, new string[]{"d", "%d"},
new string[]{"HH", "%H"}, new string[]{"H", "%H"}, new string[]{"hh", "%I"},
new string[]{"h", "%I"}, new string[]{"mm", "%M"}, new string[]{"m", "%M"},
new string[]{"ss", "%S"}, new string[]{"s", "%S"}, new string[]{"tt", "%p"},
new string[]{"t", "%p"}, new string[]{"zzz", "%z"}, new string[]{"zz", "%z"},
new string[]{"z", "%z"}
};
foreach (var change in changes)
{
//REPLACE PYTHON FORMAT WITH C# FORMAT
dateFormat = dateFormat.Replace(change[1], change[0]);
}
return dateFormat;
}
I'm afraid you can't. strftime() calls the underlying C library's strftime() function, which in turn takes formatting directives exactly in the %X form. You'll have to write a few lines of code to do a conversion.
精彩评论