Asked  6 Months ago    Answers:  5   Viewed   29 times

If I have two dates (ex. '8/18/2008' and '9/26/2008'), what is the best way to get the number of days between these two dates?

 Answers

78

If you have two date objects, you can just subtract them, which computes a timedelta object.

from datetime import date

d0 = date(2008, 8, 18)
d1 = date(2008, 9, 26)
delta = d1 - d0
print(delta.days)

The relevant section of the docs: https://docs.python.org/library/datetime.html.

See this answer for another example.

Tuesday, June 1, 2021
 
Valdas
answered 6 Months ago
74

Here's an easy way:

$depart = strtotime(implode(' ', $_POST['departon']));
$return = strtotime(implode(' ', $_POST['returnon']));

$diff = floor(($return - $depart) / (60 * 60 * 24));

Note: there's only 30 days in June.

Wednesday, March 31, 2021
 
BartmanEH
answered 9 Months ago
42

http://momentjs.com/ or https://date-fns.org/

From Moment docs:

var a = moment([2007, 0, 29]);
var b = moment([2007, 0, 28]);
a.diff(b, 'days')   // =1

or to include the start:

a.diff(b, 'days')+1   // =2

Beats messing with timestamps and time zones manually.

Depending on your specific use case, you can either

  1. Use a/b.startOf('day') and/or a/b.endOf('day') to force the diff to be inclusive or exclusive at the "ends" (as suggested by @kotpal in the comments).
  2. Set third argument true to get a floating point diff which you can then Math.floor, Math.ceil or Math.round as needed.
  3. Option 2 can also be accomplished by getting 'seconds' instead of 'days' and then dividing by 24*60*60.
Wednesday, June 9, 2021
 
treeface
answered 6 Months ago
12

One way is to extract the hour and convert minutes to hours.

There should be no need to convert to / from strings.

import pandas as pd

idx = pd.DatetimeIndex(['2016-01-01 00:30:00',
                        '2016-01-01 01:00:00',
                        '2016-01-01 01:30:00'],
                       dtype='datetime64[ns]', name='date_time', freq=None)

idx.hour + idx.minute / 60

# Float64Index([0.5, 1.0, 1.5], dtype='float64', name='date_time')
Tuesday, August 24, 2021
 
Drazisil
answered 3 Months ago
22

The issue you are coming up against comes from the fact that datetime.datetime(2012, 10, 31, 0, 0) is the 31st of the month, and not all months have a 31st. Since the rrule module is an implementation of RFC 2445. Per RFC 3.3.10:

Recurrence rules may generate recurrence instances with an invalid date (e.g., February 30) or nonexistent local time (e.g., 1:30 AM on a day where the local time is moved forward by an hour at 1:00 AM). Such recurrence instances MUST be ignored and MUST NOT be counted as part of the recurrence set.

Since you have a monthly rule that generates the 31st of a month, it will skip all months with 30 or fewer days. You can see this bug report in dateutil about this issue.

If you just want the last day of the month, you should use the bymonthday=-1 argument:

from dateutil.rrule import rrule, MONTHLY
from datetime import datetime

disclosure_start_date = datetime(2012, 10, 31, 0, 0)

rr = rrule(freq=MONTHLY, dtstart=disclosure_start_date, bymonthday=-1)
# >>>rr.between(datetime(2013, 1, 1), datetime(2013, 5, 1))
# [datetime.datetime(2013, 1, 31, 0, 0),
#  datetime.datetime(2013, 2, 28, 0, 0),
#  datetime.datetime(2013, 3, 31, 0, 0),
#  datetime.datetime(2013, 4, 30, 0, 0)]

Unfortunately, I don't think there's an RFC-compliant way to generate a simple RRULE that just falls back to the end of the month if-and-only-if it's necessary (e.g. what do you do with January 30th - you need fallback for February, but you don't want to use bymonthday=-2 because that will give you Feb. 27th, etc).

Alternatively, for a simple monthly rule like this, a better option is probably to just use relativedelta, which does fall back to the end of the month:

from dateutil.relativedelta import relativedelta
from datetime import datetime

def disclosure_dates(dtstart, rd, dtend=None):
    ii = 0
    while True:
        cdate = dtstart + ii*rd
        ii += 1

        yield cdate
        if dtend is not None and cdate >= dtend:
            break


dtstart = datetime(2013, 1, 31, 0, 0)
rd = relativedelta(months=1)
rr = disclosure_dates(dtstart, rd, dtend=datetime(2013, 5, 1))

# >>> list(rr)
# [datetime.datetime(2013, 1, 31, 0, 0),
#  datetime.datetime(2013, 2, 28, 0, 0),
#  datetime.datetime(2013, 3, 31, 0, 0),
#  datetime.datetime(2013, 4, 30, 0, 0),
#  datetime.datetime(2013, 5, 31, 0, 0)]

Note that I specifically used cdate = dtstart + ii * rd, you do not want to just keep a "running tally", as that will pin to the shortest month the tally has seen:

dt_base = datetime(2013, 1, 31)
dt = dt_base
for ii in range(5):
    cdt = dt_base + ii*rd
    print('{} | {}'.format(dt, cdt))
    dt += rd

Result:

2013-01-31 00:00:00 | 2013-01-31 00:00:00
2013-02-28 00:00:00 | 2013-02-28 00:00:00
2013-03-28 00:00:00 | 2013-03-31 00:00:00
2013-04-28 00:00:00 | 2013-04-30 00:00:00
2013-05-28 00:00:00 | 2013-05-31 00:00:00
Tuesday, October 19, 2021
 
Preet Sangha
answered 1 Month ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share