简体   繁体   中英

Get a date from iso week and year in SQL

From iso week and year, I would like to get a date. The date should be first day of the week. First day of the week is Monday. For example iso week 10 and iso year should convert to 2019-03-04. I am using Snowflake

Unfortunately, Snowflake doesn't support this functionality natively.

While it's possible to compute manually the date from ISO week and year, it's very complex. So like others suggested, generating a Date Dimension table for this is much easier.

Example of a query that can generate it for the lookups (note - this is not a full Date Dimension table - that is typically one row per day, this is one row per week).

create or replace table iso_week_lookup as 
select 
  date_part(yearofweek_iso, d) year_iso, 
  date_part(week_iso, d) week_iso, 
  min(d) first_day 
from (
  select dateadd(day, row_number() over (order by 1) - 1, '2000-01-03'::date) AS d 
  from table(generator(rowCount=>10000))
) 
group by 1, 2 order by 1,2;

select * from iso_week_lookup limit 2;
----------+----------+------------+
 YEAR_ISO | WEEK_ISO | FIRST_DAY  |
----------+----------+------------+
 2000     | 1        | 2000-01-03 |
 2000     | 2        | 2000-01-10 |
----------+----------+------------+

select min(first_day), max(first_day) from iso_week_lookup;
----------------+----------------+
 MIN(FIRST_DAY) | MAX(FIRST_DAY) |
----------------+----------------+
 2000-01-03     | 2027-05-17     |
----------------+----------------+

select * from iso_week_lookup where year_iso = 2019 and week_iso = 10;
----------+----------+------------+
 YEAR_ISO | WEEK_ISO | FIRST_DAY  |
----------+----------+------------+
 2019     | 10       | 2019-03-04 |
----------+----------+------------+

Note, you can play with the constants in create table to create a table of the range you want. Just remember to use Monday as the starting day, otherwise you'll get a wrong value for the first week in the table :)

The date expression to do this is a little complex, but not impossible:

SELECT
    DATEADD( /* Calculate start of ISOWeek as offset from Jan 1st */
      DAY,
      WEEK * 7 - CASE WHEN DAYOFWEEKISO(DATE_FROM_PARTS(YEAR, 1, 1)) < 5 THEN 7 ELSE 0 END
      + 1 - DAYOFWEEKISO(DATE_FROM_PARTS(YEAR, 1, 1)),
      DATE_FROM_PARTS(YEAR, 1, 1)
    )
FROM (VALUES (2000, 1), (2000, 2), (2001, 1), (2002, 1), (2003, 1)) v(YEAR, WEEK);

If you do not have Date Dimension table and/or utilities, as mentioned in the comments, you should parsing it from a textual form. But it would be DBMS implementation dependent:

  • In MySQL: STR_TO_DATE(CONCAT(year, ' ', week), '%x %v')
  • In PostgreSQL: TO_DATE(year || ' ' || week, 'IYYY IW')
    (also Oracle DB would be something similar)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM