Python datetime格式类似C#的String.Format
我正在把一个应用程序从C#转到Python。这个应用程序允许用户选择他们想要的日期时间格式,使用的是C#的字符串格式化日期时间。但是,Python的日期时间格式化跟C#的差得远,所以我不得不让我的代码做一些额外的工作。
有没有办法让Python解析像yyyy-MM-dd HH-mm-ss
这样的字符串,而不是%Y-%m-%d %H-%M-%S
呢?
4 个回答
1
除了选中的答案,这段内容是给那些想要在C#中实现相同功能的人,主要是把Python中的日期时间格式转换成C#可以用的日期时间格式。下面是一个扩展功能的代码,可以完成这个任务。
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;
}
2
首先运行几个替换操作:
replacelist = [["yyyy","%Y"], ["MM","%m"]] # Etc etc
for replacer in replacelist:
string.replace(replacer[0],replacer[1])
3
你可以通过简单的替换方法,把格式字符串转换得不错。
_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
我猜你的“hoops”指的应该是类似的东西。不过要注意,有些复杂的地方:
(1) C# 的格式中可以有用单引号括起来的文字(你引用的链接中有例子)
(2) 可能允许用反斜杠(比如 \
)来让某个字符变成字面量
(3) 12小时或24小时制的时间可能需要额外处理(我没有深入研究C#的规范;这个评论是基于我参与过的另一个类似的项目)。
你可能最终需要写一个编译器和一个字节码解释器来处理所有这些小问题(比如 M, F, FF, FFF 等等)。
另一个可以考虑的方案是使用 ctypes
或类似的东西,直接调用 C#
的运行时库。
更新 原来的代码过于简单,并且有个拼写错误。以下的新代码展示了如何解决一些问题(比如字面文本,以及确保输入中的字面 %
不会让 strftime 不高兴)。它没有尝试在没有直接转换的情况下给出准确的答案(比如 M, F 等等)。可能会引发异常的地方已经标注,但代码的运行是比较随意的。
_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
测试的范围如下:
>>> 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'
>>>