1

I want to create a mapping of the everyday of the week with its datetime object. So my dictionary should be having keys as "Monday", "Tuesday", .. (so on) so that I can get a datetime object for every day on the next(!) week.

At the moment I have a dictionary with these values:

DAYS_DATETIME_RELATIONS = {
    "today": datetime.datetime.now(),
    "tomorrow": datetime.datetime.now() + datetime.timedelta(days=1),
    "after_tomorrow": datetime.datetime.now() + datetime.timedelta(days=2)
}

Unfortunately I cannot find any algorithmic solution for this and hope anyone of you could help me.

Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
  • @DeepSpace yes, but I am okay with python standard library and both datetime and arrow don't provide a built-in solution for my problem. UPD: actuilly, arrow have built-in solution via function .shift(). Thank you! – Projectionist Jan 07 '18 at 09:34

4 Answers4

2

This can be achieved by using 2 dictionaries in the following manner:

import calendar
import datetime

days = {i: calendar.day_name[i-1] for i in range(7)}

today = datetime.datetime.now()

# using i % 7 so an arbitrary range can be used, for example
# range(7, 15) to get the week after the next week 
next_week = {days[i % 7]: (today + datetime.timedelta(days=i)).date()
             for i in range(7)}

print(next_week)
#  {'Tuesday': datetime.date(2018, 1, 9), 'Sunday': datetime.date(2018, 1, 7), 
#   'Monday': datetime.date(2018, 1, 8), 'Thursday': datetime.date(2018, 1, 11), 
#   'Wednesday': datetime.date(2018, 1, 10), 'Friday': datetime.date(2018, 1, 12), 
#   'Saturday': datetime.date(2018, 1, 13)}

print(next_week['Saturday'])
# 2018-01-13
DeepSpace
  • 78,697
  • 11
  • 109
  • 154
1

One very generic way will be to create a custom iterator to return you the continuos datetime objects as:

from datetime import datetime, timedelta

class RepetetiveDate(object):
    def __init__(self, day_range=7, datetime_obj=datetime.now(), jump_days=1):
        self.day_range = day_range
        self.day_counter = 0
        self.datetime_obj = datetime_obj
        self.jump_days = jump_days
        self.time_deltadiff = timedelta(days=self.jump_days)

    def __iter__(self):
        return self

    # If you are on Python 2.7
    #    define this function as `next(self)`
    def __next__(self):

        if self.day_counter >= self.day_range:
            raise StopIteration

        if self.day_counter != 0:  # don't update for the first iteration
            self.datetime_obj += self.time_deltadiff

        self.day_counter += 1
        return self.datetime_obj

Here, this iterator returns continuos datetime object starting from the datetime object you'll initially pass (default starts from current date).

It is using 3 optional params which you may customize as per your need:

  • day_range: Maximum allowed iteration for the RepetetiveDate iterator. Default value is 7.

  • jump_days: Integer value for jumping the number of days for the datetime object in next iteration. That means, if jump_days is equal to "2", will return datetime objects of every alternate date. To get the datetime objects of past, pass this value as negative. Default value is 1.

  • datetime_obj: Accepts the datetime from which date you want to start your iteration. Default value is current date.

If you are new to iterators, take a look at:

Sample Run for upcoming dates:

>>> x = RepetetiveDate()
>>> next(x)
datetime.datetime(2018, 1, 8, 15, 55, 39, 124654)
>>> next(x)
datetime.datetime(2018, 1, 9, 15, 55, 39, 124654)
>>> next(x)
datetime.datetime(2018, 1, 10, 15, 55, 39, 124654)

Sample Run for previous dates:

>>> x = RepetetiveDate(jump_days=-1)
>>> next(x)
datetime.datetime(2018, 1, 6, 15, 55, 39, 124654)
>>> next(x)
datetime.datetime(2018, 1, 5, 15, 55, 39, 124654)
>>> next(x)
datetime.datetime(2018, 1, 4, 15, 55, 39, 124654)

How to get your desired dictionary?

Using this, you may create your dictionary using the dict comprehension as:

  • Dictionary of all days of week

    >>> {d.strftime("%A"): d for d in RepetetiveDate(day_range=7)}
    { 
        'Monday': datetime.datetime(2018, 1, 8, 15, 23, 16, 926364),
        'Tuesday': datetime.datetime(2018, 1, 9, 15, 23, 16, 926364), 
        'Wednesday': datetime.datetime(2018, 1, 10, 15, 23, 16, 926364), 
        'Thursday': datetime.datetime(2018, 1, 11, 15, 23, 16, 926364),
        'Friday': datetime.datetime(2018, 1, 12, 15, 23, 16, 926364), 
        'Saturday': datetime.datetime(2018, 1, 13, 15, 23, 16, 926364), 
        'Sunday': datetime.datetime(2018, 1, 14, 15, 23, 16, 926364)
    }
    

    Here I am using d.strftime("%A") to extract day name from the datetime object.

  • List of current days for next 4 weeks

    >>> [d for d in RepetetiveDate(jump_days=7, day_range=4))]
    [
        datetime.datetime(2018, 1, 7, 16, 17, 45, 45005), 
        datetime.datetime(2018, 1, 14, 16, 17, 45, 45005), 
        datetime.datetime(2018, 1, 21, 16, 17, 45, 45005),
        datetime.datetime(2018, 1, 28, 16, 17, 45, 45005)
    ]
    
Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
1

Here is another way to solve your question using datetime and timedelta from datetime module:

from datetime import datetime, timedelta

def generate_dict_relation(_time, _days=0):
    keys = {'Yesterday': -1, 'Today': 0, 'Tomorow': 1, 'After_tomorrow': 2}

    if not _days:
        return {key: _time + timedelta(days=keys.get(key, 0)) for key in keys}
    else:
        return {(_time + timedelta(days=_days+k)).strftime('%A'): _time + timedelta(days=_days+k)
                    for k in range(0, 7)}

_date_now = datetime.now()
DAYS_DATETIME_RELATIONS = {}
# get dates: yesterday, today, tomorrow and after tomorrow
DAYS_DATETIME_RELATIONS.update(generate_dict_relation(_date_now, 0))
# get dates after 7 days = 1 week
DAYS_DATETIME_RELATIONS.update(generate_dict_relation(_date_now, 7))

next_tuesday = DAYS_DATETIME_RELATIONS.get('Tuesday')
next_monday = DAYS_DATETIME_RELATIONS.get('Monday')
yesterday = DAYS_DATETIME_RELATIONS.get('Yesterday')

print('{0:%d/%m/%Y %H:%M:%S:%s} \t {1}'.format(next_tuesday, repr(next_tuesday)))
print('{0:%d/%m/%Y %H:%M:%S:%s} \t {1}'.format(next_monday, repr(next_monday)))
print('{0:%d/%m/%Y %H:%M:%S:%s} \t {1}'.format(yesterday, repr(yesterday)))

Output:

16/01/2018 10:56:26:1516096586   datetime.datetime(2018, 1, 16, 10, 56, 26, 659949)
15/01/2018 10:56:26:1516010186   datetime.datetime(2018, 1, 15, 10, 56, 26, 659949)
06/01/2018 10:56:26:1515232586   datetime.datetime(2018, 1, 6, 10, 56, 26, 659949)
Chiheb Nexus
  • 9,104
  • 4
  • 30
  • 43
1

One very clean way to implement this is using rrule from the dateutil library. For example:

>>> from dateutil.rrule import rrule, DAILY
>>> from datetime import datetime
>>> start_date = datetime.now()

>>> {d.strftime("%A"): d for d in rrule(freq=DAILY, count=7, dtstart=start_date)}

which will return your desired dict object:

{  
     'Sunday': datetime.datetime(2018, 1, 7, 17, 2, 30),
     'Monday': datetime.datetime(2018, 1, 8, 17, 2, 30), 
     'Tuesday': datetime.datetime(2018, 1, 9, 17, 2, 30), 
     'Wednesday': datetime.datetime(2018, 1, 10, 17, 2, 30),
     'Thursday': datetime.datetime(2018, 1, 11, 17, 2, 30),
     'Friday': datetime.datetime(2018, 1, 12, 17, 2, 30), 
     'Saturday': datetime.datetime(2018, 1, 13, 17, 2, 30)
}

(Special thanks to Jon Clements for telling me about rrule)

Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126