如何在yaml中创建datetime.time()对象?

4
我知道我可以创建一个 datetime.datetime 对象,然后使用 .time() 方法,如下所示:

my_file.yaml

MyDateTime: 2015-08-11 10:08:37

并且:
In [58]: f = open("my_file.yaml", "rU")

In [59]: temp = yaml.safe_load(f)

In [60]: f.close()

In [61]: temp['MyDateTime'].time()
Out[61]: datetime.time(10, 8, 37)

但是这似乎有点冗余,是否有一种方法可以首先创建 datetime.time() 对象?


可能是Formatting custom class output in PyYAML的重复问题。 - larsks
请参考相关问题:https://dev59.com/3sBpzogBFxS5KdRjwuD- - Mihai8
1个回答

2
你可以修补SafeLoader来满足你的需求,但最好创建一个新的Loader,它与safe_load()使用的SafeLoader相同。 你需要提供的唯一内容是在匹配到时间戳标量时调用的方法(construct_yaml_time()),并通过调用add_constructor指定它。
import ruamel.yaml as yaml

from ruamel.yaml.loader import Reader, Scanner, Composer, SafeConstructor, \
     Resolver, Parser

class TimeConstructor(SafeConstructor):
    def __init__(self):
        SafeConstructor.__init__(self)

    def construct_yaml_time(self, node):
        x = SafeConstructor.construct_yaml_timestamp(self, node)
        return x.time()


TimeConstructor.add_constructor(
    u'tag:yaml.org,2002:timestamp',
    TimeConstructor.construct_yaml_time)

class TimeLoader(Reader, Scanner, Parser, Composer, TimeConstructor, Resolver):
    def __init__(self, stream):
        Reader.__init__(self, stream)
        Scanner.__init__(self)
        Parser.__init__(self)
        Composer.__init__(self)
        TimeConstructor.__init__(self)
        Resolver.__init__(self)

yaml_str = """\
MyDateTime: 2015-08-11 10:08:37
x: 23423
"""

data = yaml.load(yaml_str, Loader=TimeLoader)
print data

给你:

<type 'datetime.time'>
{'x': 23423, 'MyDateTime': datetime.time(10, 8, 37)}

您也可以将时间对象指定为10:08:37,但这将以六十进制数加载它们,并将其转换为整数(在本例中为36517)。您当然也可以更改此行为:
import ruamel.yaml as yaml

from ruamel.yaml.loader import Reader, Scanner, Composer, SafeConstructor, \
     Resolver, Parser

import datetime

class TimeConstructor(SafeConstructor):
    def __init__(self):
        SafeConstructor.__init__(self)

    def construct_yaml_time(self, node):
        value = self.construct_scalar(node)
        if ':' not in value:
            return SafeConstructor.construct_yaml_int(self, node)
        return datetime.time(*[int(x) for x in value.split(':')])



TimeConstructor.add_constructor(
    u'tag:yaml.org,2002:int',
    TimeConstructor.construct_yaml_time)

class TimeLoader(Reader, Scanner, Parser, Composer, TimeConstructor, Resolver):
    def __init__(self, stream):
        Reader.__init__(self, stream)
        Scanner.__init__(self)
        Parser.__init__(self)
        Composer.__init__(self)
        TimeConstructor.__init__(self)
        Resolver.__init__(self)

yaml_str = """\
MyDateTime: 10:08:37
x: 12345
"""

data = yaml.load(yaml_str, Loader=TimeLoader)
print data

这将会得到:

{'x': 12345, 'MyDateTime': datetime.time(10, 8, 37)}

这取决于时间是否被普通的int识别器所识别。您也可以识别六十进制本身,但在我的经验中,这更加复杂。其他选择包括通过明确标记datetime.time对象并提供加载(和可能的保存)例程来创建它们。

我犯了同样的错误。他要求获取一个 datetime.time 对象,而不是 datetime.datetime 对象。幸运的是,这个问题竟然是一个有现成好答案的重复问题 @ https://dev59.com/1oTca4cB1Zd3GeqPAeJp - larsks
@larsks 谢谢,我不应该在长时间工作后的深夜回答问题。 - Anthon
谢谢,根据你的回答和larsks提供的链接,看起来没有简单的方法可以做到这一点。 - Akavall
@Akavall 没有,我提供了一种替代方案,允许您在没有前置日期的情况下编写时间,但是与日期时间戳和时间持续时间(性格)一样,没有内置支持时间对象。 - Anthon
谢谢你的帮助! - Akavall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接