I know that I can create a datetime.datetime object and then use .time() method, like this:
my_file.yaml
MyDateTime: 2015-08-11 10:08:37
and then:
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)
but that seems a little redundant, is there a way to create datetime.time() object to begin with?
You can patch the SafeLoader to do your bidding, but it is nicer to make a new Loader that does the same as the SafeLoader used by safe_load().
The only thing you need to provide for that is a method that is invoked (construct_yaml_time()) when a timestamp scalar is matched and specify it by calling 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
gives you:
<type 'datetime.time'>
{'x': 23423, 'MyDateTime': datetime.time(10, 8, 37)}
You can also specify your time objects as 10:08:37 but this will load them as sexagesimal number and that will convert them to an integer (36517 in this case). You can, of course, change this behaviour as well:
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
which gives:
{'x': 12345, 'MyDateTime': datetime.time(10, 8, 37)}
This relies on the time to be recognised by the normal int recogniser. You can also recognise the sexagesimal itself, but that is more complex to implement in my experience.
Other alternatives exists, including creating datetime.time objects by tagging them explicitly and providing loading (and possible saving) routines.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With