14

Apologies if this is an easy one but I can't see anything in the numpy documentation. I have a datetime64 and I'd like to find out which day of the week it is.

Unlike python datetime, datetime64 doesn't seem to have a .weekday() function. However it does have a busday_offset() function, which implies it must know behind-the-scenes what day of the week a given date is. Any help greatly appreciated.

Praveen
  • 8,945
  • 4
  • 31
  • 49
Chris J Harris
  • 1,597
  • 2
  • 14
  • 26

5 Answers5

22

Please look at the following related SO question:

Get weekday/day-of-week for Datetime column of DataFrame

I understand that your data is a numpy array, it may be useful to convert your data into a dataframe format via pandas. This is shown below.

import pandas as pd
df = pd.DataFrame(numpyArray)

Provided your data is now in a dataframe, then the below code (taken from the above link), should provide you with the weekday you are after.

df['weekday'] = df['Timestamp'].dt.dayofweek

Sample Output

Additionally this reference may also assist you.

https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.dt.dayofweek.html

IronKirby
  • 708
  • 1
  • 7
  • 24
  • 1
    @roganjosh - No worries. I just thought that so I started editing my answer. Thanks for the heads up! – IronKirby Sep 19 '18 at 05:43
  • thanks - this definitely works, but I am using this within a loop that runs (on average) 100 000 times - so I am trying to avoid stepping into pandas-land. – Chris J Harris Sep 19 '18 at 06:07
  • @Chrisper - No worries. If I knew that, I'd suggest a lambda function you could implement which would enable this to run just as fast even with pandas. – IronKirby Sep 19 '18 at 23:41
12

If you're looking for a genuinely vectorized numpy approach, you could do:

def day_of_week_num(dts):
    return (dts.astype('datetime64[D]').view('int64') - 4) % 7

It's a bit hacky, and just takes advantage of the fact that numpy.datetime64s are relative to the unix epoch, which was a Thursday.

(I don't know if this is an implementational detail that could change without notice, but you can always check with assert np.zeros(1).astype('datetime64[D]') == np.datetime64('1970-01-01', 'D').)

jwdink
  • 4,824
  • 5
  • 18
  • 20
  • 1
    thanks - that actually works very well. For a year's worth of dates, it runs about 10x faster than checking .isoweekday() – Chris J Harris Jan 23 '19 at 04:31
  • 1
    Instead of using the assertion, you can compute the shift via a known date. That is, instead of the `4` use `(np.datetime64('2020-01-06', 'D')-np.datetime64('2020-01-06', 'W')).astype(int)`. Jan 6 2020 was a Monday. Of course, this will evaluate to `4` unless `numpy` changes its behaviour. – Samufi Jun 10 '20 at 23:01
8

I think you could do in this way:

import numpy as np
import datetime
t = '2018-09-19'
t = np.datetime64(t)
day = t.astype(datetime.datetime).isoweekday()
print day

Output:

3
Joe
  • 12,057
  • 5
  • 39
  • 55
  • thanks! - I guess this is as good as it's going to get - seems odd that the functionality doesn't exist within numpy though. – Chris J Harris Sep 19 '18 at 06:10
  • @Chrisper you're correct that it is odd, but it is a characteristic of so-called "OO" languages that they inadequately deal with polymorphism and type inference. It gets even worse when you start dealing with "data wrangling" to get various "shapes" morphed properly, etc. This has to take up the majority of programmer hours. – user3673 Nov 16 '20 at 18:36
  • 2
    By the way, this answer doesn't work. `numpy.datetime64('2020-10-27T22:29:00.000000000').astype(datetime.datetime).__class__` is `` – user3673 Nov 16 '20 at 18:41
  • @user3673 - I couldn't agree more - I do most of my coding in Scala these days. – Chris J Harris Nov 16 '20 at 22:49
0

Something like this could help. It takes a pandas series or data frame column as an input and returns a dictionary having the desired attributes for all unique DATETIME values in the target series/column.

def compute_dateparts(fld):
  fld_dtype = type(fld[0])
  fld = fld.unique()
  if isinstance(fld_dtype, pd.core.dtypes.dtypes.DatetimeTZDtype):
    fld_dtype = np.datetime64
  if not np.issubdtype(fld_dtype, np.datetime64):
    fld = pd.to_datetime(fld, infer_datetime_format=True)

  out = dict()
  for attr in ['Dayofweek', 'Is_month_end', 'Is_month_start','Is_quarter_end', 'Is_quarter_start', 'Is_year_end', 'Is_year_start']:
    out[attr] = pd.Series(getattr(fld, attr.lower()),index=fld).to_dict()

  return out
0

Here is a simple and practial way to get the day of the week and the start and end date of any week in a year, directly using np.datetime64 and np.timedelta64

def dayofweek(d):
    """Return dayofweek (0..7)."""
    d = np.datetime64(d) # d can be string or np.datetime64
    return  int((d - np.datetime64('1969-12-29', 'D')) / np.timedelta64(1, 'D') % 7)

def week(yr, wk):
    """return start and end date of given week in given year."""
    if wk > 53:
        yr, wk = wk, yr # in case you forgot order of yr and wk
    d = np.datetime64(str(yr), 'D') + (wk - 1) * np.timedelta64(7, 'D')
    week_start = d - dayofweek(d)
    week_end = week_start + np.timedelta64(6, 'D')
    return week_start, week_end
theo olsthoorn
  • 455
  • 3
  • 6