How to use strftime in jalali date in python? - python

I need convert ''1396/4/28'' to ''1396/04/28'' in persian date.
Code:
from service import jalali
now_date = datetime.datetime.now() // 2017-07-19 21:32:34.574369
date = now_date.strftime('%Y/%m/%d') // 2017-07-19
from_date = jalali.Gregorian(date).persian_string("{}/{}/{}") // '1396/4/28'
How to convert ''1396/4/28'' to ''1396/04/28'' in persian date in python ?

With strptime:
from datetime import datetime
from service import jalali
from_date = jalali.Gregorian(date).persian_string("{}/{}/{}")
print datetime.strptime('1396/4/28', '%Y/%m/%d')
print datetime.strptime(from_date, '%Y/%m/%d')
> datetime.datetime(1396, 4, 28, 0, 0)
> datetime.datetime(1396, 4, 28, 0, 0)
If you mean how to print a date like this with strftime - that is not possible for dates <1900. Print it manually instead:
print ("%04d/%02d/%02d" % (date.year, date.month, date.day))
> 1396/04/28

You can use PersianTools:
from persiantools.jdatetime import JalaliDateTime
import datetime
now_date = datetime.datetime.now() # datetime.datetime(2021, 2, 11, 15, 1, 57, 256596)
from_date = JalaliDateTime.to_jalali(now_date) # JalaliDateTime(1399, 11, 23, 15, 1, 57, 256596)
from_date.strftime("%Y/%m/%d") # '1399/11/23'

Related

dateutil parser for month/year strings

Somewhat related to this post: dateutil parser for month/year format: return beginning of month
Given a date string of the form 'Sep-2020', dateutil.parser.parse correctly identifies the month and the year but adds the day as well. If a default is provided, it takes the day from it. Else, it will just use today's day. Is there anyway to tell if the parser used any of the default terms?
For example, how can I tell from the three options below that the input date string in the first case did not include day and that the default value was used?
>>> from datetime import datetime
>>> from dateutil import parser
>>> d = datetime(1978, 1, 1, 0, 0)
>>> parser.parse('Sep-2020', default=d)
datetime.datetime(2020, 9, 1, 0, 0)
>>> parser.parse('1-Sep-2020', default=d)
datetime.datetime(2020, 9, 1, 0, 0)
>>> parser.parse('Sep-1-2020', default=d)
datetime.datetime(2020, 9, 1, 0, 0)
``
I did something a little mad to solve this. It's mad since it's not guaranteed to work with future versions of dateutil (since it's relying on some dateutil internals).
Currently I'm using: python-dateutil 2.8.1.
I wrote my own class and passed it as default to the parser:
from datetime import datetime
class SentinelDateTime:
def __init__(self, year=0, month=0, day=0, default=None):
self._year = year
self._month = month
self._day = day
if default is None:
default = datetime.now().replace(
hour=0, minute=0,
second=0, microsecond=0
)
self.year = default.year
self.month = default.month
self.day = default.day
self.default = default
#property
def has_year(self):
return self._year != 0
#property
def has_month(self):
return self._month != 0
#property
def has_day(self):
return self._day != 0
def todatetime(self):
res = {
attr: value
for attr, value in [
("year", self._year),
("month", self._month),
("day", self._day),
] if value
}
return self.default.replace(**res)
def replace(self, **result):
return SentinelDateTime(**result, default=self.default)
def __repr__(self):
return "%s(%d, %d, %d)" % (
self.__class__.__qualname__,
self._year,
self._month,
self._day
)
The dateutils method now returns this SentinelDateTime class:
>>> from dateutil import parser
>>> from datetime import datetime
>>> from snippet1 import SentinelDateTime
>>>
>>> sentinel = SentinelDateTime()
>>> s = parser.parse('Sep-2020', default=sentinel)
>>> s
SentinelDateTime(2020, 9, 0)
>>> s.has_day
False
>>> s.todatetime()
datetime.datetime(2020, 9, 9, 0, 0)
>>> d = datetime(1978, 1, 1)
>>> sentinel = SentinelDateTime(default=d)
>>> s = parser.parse('Sep-2020', default=sentinel)
>>> s
SentinelDateTime(2020, 9, 0)
>>> s.has_day
False
>>> s.todatetime()
datetime.datetime(2020, 9, 1, 0, 0)
I wrote this answer into a little package: https://github.com/foxyblue/sentinel-datetime
I have found a solution that's a little less complicated:
from datetime import datetime
from dataclasses import dataclass
from dateutil import parser
#dataclass
class Result:
dt: datetime
data: dict
class subparser(parser.parser):
def _build_naive(self, res, default):
naive = super()._build_naive(res, default)
return Result(dt=naive, data=res)
In an example:
>>> PARSER = subparser()
>>> info = PARSER.parse("2020")
>>> info.data.year)
2020
>>> info.data.month
None
>>> info.dt
2020-01-10 00:00:00

Add a timestamp to data simulator

I am simulating time series data using Python TestData and trying to add a new key value (event_time) that includes a time stamp when the record is generated. The issue is that the field is not incrementing as the script runs, just at first execution. Is there a simple way to do this?
import testdata
import datetime
EVENT_TYPES = ["USER_DISCONNECT", "USER_CONNECTED", "USER_LOGIN", "USER_LOGOUT"]
class EventsFactory(testdata.DictFactory):
event_time = testdata.DateIntervalFactory(datetime.datetime.now(), datetime.timedelta(minutes=0))
start_time = testdata.DateIntervalFactory(datetime.datetime.now(), datetime.timedelta(minutes=12))
end_time = testdata.RelativeToDatetimeField("start_time", datetime.timedelta(minutes=20))
event_code = testdata.RandomSelection(EVENT_TYPES)
for event in EventsFactory().generate(100):
print event
Outputs:
{'start_time': datetime.datetime(2016, 6, 21, 17, 47, 50, 422020), 'event_code': 'USER_CONNECTED', 'event_time': datetime.datetime(2016, 6, 21, 17, 47, 50, 422006), 'end_time': datetime.datetime(2016, 6, 21, 18, 7, 50, 422020)}
{'start_time': datetime.datetime(2016, 6, 21, 17, 59, 50, 422020), 'event_code': 'USER_CONNECTED', 'event_time': datetime.datetime(2016, 6, 21, 17, 47, 50, 422006), 'end_time': datetime.datetime(2016, 6, 21, 18, 19, 50, 422020)}
{'start_time': datetime.datetime(2016, 6, 21, 18, 11, 50, 422020), 'event_code': 'USER_LOGOUT', 'event_time': datetime.datetime(2016, 6, 21, 17, 47, 50, 422006), 'end_time': datetime.datetime(2016, 6, 21, 18, 31, 50, 422020)}
So the timedelta() is how much into the future you want the event to happen. Notice that the timedelta(minutes=12) causes the time between each start_time generated to be 12 minutes from datetime.datetime.now() from the previous iteration of the for-loop (not the execution of the script). Similarly, the end_time is a relative timedelta(minutes=20) to start_time so it will always be 20 minutes in front of start_time. Your event_time is not incrementing because it has no delta (change) value for any time the code is run, and it will always use the datetime.datetime.now() from the time the script is run.
It if is test data, I think you would be looking for something like
import testdata
import datetime
EVENT_TYPES = ["USER_DISCONNECT", "USER_CONNECTED", "USER_LOGIN", "USER_LOGOUT"]
class EventsFactory(testdata.DictFactory):
start_time = testdata.DateIntervalFactory(datetime.datetime.now(), datetime.timedelta(minutes=12))
event_time = testdata.RelativeToDatetimeField("start_time", datetime.timedelta(minutes=10))
end_time = testdata.RelativeToDatetimeField("start_time", datetime.timedelta(minutes=20))
event_code = testdata.RandomSelection(EVENT_TYPES)
for event in EventsFactory().generate(100):
print event
Edit: if it doesn't have to do with the data provided:
So the testdata.DictFactory that you are passing in just creates a dictionary based on the instance variables you create as far as I can see.
You want an event_time instance variable that gets the time for every iteration of the for-loop, to do that it would look like:
import testdata
import datetime
EVENT_TYPES = ["USER_DISCONNECT", "USER_CONNECTED", "USER_LOGIN", "USER_LOGOUT"]
class EventsFactory(testdata.DictFactory):
start_time = testdata.DateIntervalFactory(datetime.datetime.now(), datetime.timedelta(minutes=12))
end_time = testdata.RelativeToDatetimeField("start_time", datetime.timedelta(minutes=20))
event_time = datetime.datetime.now()
event_code = testdata.RandomSelection(EVENT_TYPES)
for event in EventsFactory().generate(100):
print event
If I am understanding what you are wanting correctly, this should achieve it in the output.
Edit 2:
After looking at this again this may not achieve what you are wanting because EventsFactory().generate(100) seems to instantiate all 100 at the same time, and to get a dictionary key of event_time you would have to use the testdata.RelativeToDatetimeField() method to change the time
for event in EventsFactory().generate(10):
event["event_time"] = datetime.datetime.now()
print event

Date String to Time tuple

I am trying to pass a string into as function and need to convert it into a time tuple:
def sim(startdate, enddate):
# need to convert the date from string to integer time tuple:
dt_start = dt.date(startdate)
print 'Start Date: ', dt_start
dt_end = dt.date(enddate)
print 'End Date: ', dt_end
# in String format
sim('Jan 1, 2011', 'Dec 31, 2011')
# in interger in string format
sim('2011,1,1', '2011,12,31')
Another way would be to use strptime(). Have a time format defined for both of your formats and use them accordingly. This is what I mean:
import datetime as dt
def sim(startdate, enddate):
time_format_one = "%b %d, %Y"
time_format_two = "%Y,%m,%d"
try:
dt_start = dt.datetime.strptime(startdate, time_format_one)
dt_end = dt.datetime.strptime(enddate, time_format_one)
except ValueError:
dt_start = dt.datetime.strptime(startdate, time_format_two)
dt_end = dt.datetime.strptime(enddate, time_format_two)
print 'Start Date: ', dt_start.date()
print 'End Date: ', dt_end.date()
# in String format
sim('Jan 1, 2011', 'Dec 31, 2011')
# in interger in string format
sim('2011,1,1', '2011,12,31')
prints:
Start Date: 2011-01-01
End Date: 2011-12-31
Start Date: 2011-01-01
End Date: 2011-12-31
You could use timetuple() on dt_start and dt_end if you need time tuple.
I assume you want to convert date ('Jan 1, 2011', 'Dec 31, 2011') and ('2011,1,1', '2011,12,31') into timetuple
from datetime import datetime
date_str = "Jan 1, 2011"
fmt = "%b %d, %Y"
# Construct a datetime object
date_obj = datetime.strptime(date_str, fmt)
# Convert it to any string format you want
new_fmt = "%Y, %m, %d"
print date_obj.strftime(new_fmt)
# Prints'2011, 01, 01'
# If you want python timetuple then
t_tuple = date_obj.timetuple()
What you're probably trying to do is the following:
import datetime as dt
year,month,day = map(int, '2011,1,1'.split(','))
dt_start = dt.date(year,month,day)
print dt_start # prints 2011-01-01
The error is because of the use of a string '2011,1,1' instead of integers: 2011,1,1 as an input to: datetime.date()

how to store and access datetime(s) in a Python object that needs to be converted into JSON?

I'm working on my first python script, which creates and updates and object with different datetime entries.
I'm setting up the object like this:
# Date conversion
import datetime
import time
# 0:01:00 and 0:00:00 threshold and totalseconds
threshold = time.strptime('00:01:00,000'.split(',')[0],'%H:%M:%S')
tick = datetime.timedelta(hours=threshold.tm_hour,minutes=threshold.tm_min,seconds=threshold.tm_sec).total_seconds()
zero_time = datetime.timedelta(hours=0,minutes=0,seconds=0)
zero_tick = zero_time.total_seconds()
format_date = '%d/%b/%Y:%H:%M:%S'
from datetime import datetime
# Response object
class ResponseObject(object):
def __init__(self, dict):
self.__dict__ = dict
# JSON encoding
from json import JSONEncoder
class MyEncoder(JSONEncoder):
def default(self, o):
return o.__dict__
# > check for JSON response object
try:
obj
except NameError:
obj = ResponseObject({})
...
entry = "14/Nov/2012:09:32:31 +0100"
entry_tz = str.join(' ', entry.split(None)[1:6])
entry_notz = entry.replace(' '+entry_tz,'')
this_time = datetime.strptime(entry_notz, format_date)
# > add machine to object if not there, add init time
if not hasattr(obj, "SOFTINST"):
#line-breaks for readability
setattr(obj, "SOFTINST", {
"init":this_time,
"last":this_time,
"downtime":zero_time,
"totaltime":"",
"percentile":100
})
...
print this_time
print MyEncoder().encode({"hello":"bar"})
print getattr(obj, "SOFTINST")
My last 'print' returns this:
{
'totaltime': datetime.timedelta(0),
'uptime': '',
'last': datetime.datetime(2012, 11, 14, 9, 32, 31),
'init': datetime.datetime(2012, 11, 14, 9, 32, 31),
'percentile': 100,
'downtime': 0
}
Which I cannot convert into JSON...
I don't understand why this:
print this_time #2012-11-14 09:32:31
but inside the object, it's stored as
datetime.datetime(2012, 11, 14, 9, 32, 31)
Question:
How do I store datetime objects in "string format" and still have them easily accessible (and modifyable) in Python?
Thanks!
Use the isoformat method on the datetime object. (see reference: http://docs.python.org/release/2.5.2/lib/datetime-datetime.html)

How to increment a datetime by one day?

How to increment the day of a datetime?
for i in range(1, 35)
date = datetime.datetime(2003, 8, i)
print(date)
But I need pass through months and years correctly? Any ideas?
date = datetime.datetime(2003,8,1,12,4,5)
for i in range(5):
date += datetime.timedelta(days=1)
print(date)
Incrementing dates can be accomplished using timedelta objects:
import datetime
datetime.datetime.now() + datetime.timedelta(days=1)
Look up timedelta objects in the Python docs: http://docs.python.org/library/datetime.html
All of the current answers are wrong in some cases as they do not consider that timezones change their offset relative to UTC. So in some cases adding 24h is different from adding a calendar day.
Proposed solution
The following solution works for Samoa and keeps the local time constant.
def add_day(today):
"""
Add a day to the current day.
This takes care of historic offset changes and DST.
Parameters
----------
today : timezone-aware datetime object
Returns
-------
tomorrow : timezone-aware datetime object
"""
today_utc = today.astimezone(datetime.timezone.utc)
tz = today.tzinfo
tomorrow_utc = today_utc + datetime.timedelta(days=1)
tomorrow_utc_tz = tomorrow_utc.astimezone(tz)
tomorrow_utc_tz = tomorrow_utc_tz.replace(hour=today.hour,
minute=today.minute,
second=today.second)
return tomorrow_utc_tz
Tested Code
# core modules
import datetime
# 3rd party modules
import pytz
# add_day methods
def add_day(today):
"""
Add a day to the current day.
This takes care of historic offset changes and DST.
Parameters
----------
today : timezone-aware datetime object
Returns
-------
tomorrow : timezone-aware datetime object
"""
today_utc = today.astimezone(datetime.timezone.utc)
tz = today.tzinfo
tomorrow_utc = today_utc + datetime.timedelta(days=1)
tomorrow_utc_tz = tomorrow_utc.astimezone(tz)
tomorrow_utc_tz = tomorrow_utc_tz.replace(hour=today.hour,
minute=today.minute,
second=today.second)
return tomorrow_utc_tz
def add_day_datetime_timedelta_conversion(today):
# Correct for Samoa, but dst shift
today_utc = today.astimezone(datetime.timezone.utc)
tz = today.tzinfo
tomorrow_utc = today_utc + datetime.timedelta(days=1)
tomorrow_utc_tz = tomorrow_utc.astimezone(tz)
return tomorrow_utc_tz
def add_day_dateutil_relativedelta(today):
# WRONG!
from dateutil.relativedelta import relativedelta
return today + relativedelta(days=1)
def add_day_datetime_timedelta(today):
# WRONG!
return today + datetime.timedelta(days=1)
# Test cases
def test_samoa(add_day):
"""
Test if add_day properly increases the calendar day for Samoa.
Due to economic considerations, Samoa went from 2011-12-30 10:00-11:00
to 2011-12-30 10:00+13:00. Hence the country skipped 2011-12-30 in its
local time.
See https://stackoverflow.com/q/52084423/562769
A common wrong result here is 2011-12-30T23:59:00-10:00. This date never
happened in Samoa.
"""
tz = pytz.timezone('Pacific/Apia')
today_utc = datetime.datetime(2011, 12, 30, 9, 59,
tzinfo=datetime.timezone.utc)
today_tz = today_utc.astimezone(tz) # 2011-12-29T23:59:00-10:00
tomorrow = add_day(today_tz)
return tomorrow.isoformat() == '2011-12-31T23:59:00+14:00'
def test_dst(add_day):
"""Test if add_day properly increases the calendar day if DST happens."""
tz = pytz.timezone('Europe/Berlin')
today_utc = datetime.datetime(2018, 3, 25, 0, 59,
tzinfo=datetime.timezone.utc)
today_tz = today_utc.astimezone(tz) # 2018-03-25T01:59:00+01:00
tomorrow = add_day(today_tz)
return tomorrow.isoformat() == '2018-03-26T01:59:00+02:00'
to_test = [(add_day_dateutil_relativedelta, 'relativedelta'),
(add_day_datetime_timedelta, 'timedelta'),
(add_day_datetime_timedelta_conversion, 'timedelta+conversion'),
(add_day, 'timedelta+conversion+dst')]
print('{:<25}: {:>5} {:>5}'.format('Method', 'Samoa', 'DST'))
for method, name in to_test:
print('{:<25}: {:>5} {:>5}'
.format(name,
test_samoa(method),
test_dst(method)))
Test results
Method : Samoa DST
relativedelta : 0 0
timedelta : 0 0
timedelta+conversion : 1 0
timedelta+conversion+dst : 1 1
Here is another method to add days on date using dateutil's relativedelta.
from datetime import datetime
from dateutil.relativedelta import relativedelta
print 'Today: ',datetime.now().strftime('%d/%m/%Y %H:%M:%S')
date_after_month = datetime.now()+ relativedelta(day=1)
print 'After a Days:', date_after_month.strftime('%d/%m/%Y %H:%M:%S')
Output:
Today: 25/06/2015 20:41:44
After a Days: 01/06/2015 20:41:44
Most Simplest solution
from datetime import timedelta, datetime
date = datetime(2003,8,1,12,4,5)
for i in range(5):
date += timedelta(days=1)
print(date)
This was a straightforward solution for me:
from datetime import timedelta, datetime
today = datetime.today().strftime("%Y-%m-%d")
tomorrow = datetime.today() + timedelta(1)
You can also import timedelta so the code is cleaner.
from datetime import datetime, timedelta
date = datetime.now() + timedelta(seconds=[delta_value])
Then convert to date to string
date = date.strftime('%Y-%m-%d %H:%M:%S')
Python one liner is
date = (datetime.now() + timedelta(seconds=[delta_value])).strftime('%Y-%m-%d %H:%M:%S')
A short solution without libraries at all. :)
d = "8/16/18"
day_value = d[(d.find('/')+1):d.find('/18')]
tomorrow = f"{d[0:d.find('/')]}/{int(day_value)+1}{d[d.find('/18'):len(d)]}".format()
print(tomorrow)
# 8/17/18
Make sure that "string d" is actually in the form of %m/%d/%Y so that you won't have problems transitioning from one month to the next.

Categories

Resources