在Postgresql中获得ISO Date的奇怪结果

时间:2016-02-13 06:03:05

标签: postgresql date sum dayofweek isodate

我有一个表task_details。我需要从此表中选择每周日期。我使用过 ISO年度& ISO Week 从此表中提取每周日期,因为我想在2015年12月28日,12月28日,12月30日,12月31日和1月1日提取其周数为53 ' 16,2 Jan' 16因为这些日期不应分为两个不同的星期。
我用于 ISO年度&的查询 ISO Week 如下。

select
    name, id,
    to_date(week || ' ' || yr, 'IW IYYY') week_date,
    sum(worked_hours) worked_hours_per_week,
    week, yr
from (
    select
        name, id,
        newdate, hours worked_hours,
        to_number(to_char(newdate, 'IW'), '99') week,
        extract( year from newdate) yr
    from task_details t
) sub
where worked_hours > 0 
group by name, id, to_date(week || ' ' || yr, 'IW IYYY'), week, yr 
order by yr, week

这几周工作正常,但后来我得到了一个奇怪的结果,一个日期记录在表中。
该表没有2017年的数据。此外, yr 列显示2016年符合预期,但 newdate 列和列产生了奇怪的结果。为什么会这样?我该如何解决这个问题?

以下是它的SQL小提琴:http://sqlfiddle.com/#!15/53abf/1

2 个答案:

答案 0 :(得分:2)

您不应在提取函数中混用weekyear,因为year是格里高利历,而不是特殊的ISO日历。

请参阅section 9.9.1 and comments about week

to_number(to_char(newdate, 'IW'), '99')实际上是extract(week from newdate)

yr列更改为extract(isoyear from newdate)可以解决您的问题。

Adjusted SQL Fiddle

答案 1 :(得分:1)

@gwaigh已经清除了你对格里高利和ISO年的混淆。

但是,使用date_trunc()获取每周的第一天,您的查询会更简单,更快捷:

SELECT name, id
     , date_trunc('week', newdate)::date AS week_date
     , extract(week FROM newdate)::int       AS week
     , extract(isoyear from newdate)::int    AS isoyr  -- must be ISO year to match
     , sum(hours)                            AS worked_hours_per_week
FROM   task_details
WHERE  hours > 0
GROUP  BY name, id, week_date, week, yr
ORDER  BY week_date;

还简化了您的查询。

SQL Fiddle.

无论哪种方式,如果您使用timestamptz,则年,周或日期取决于您当前的时区设置。 (这可能是另一年,取决于你现在的位置。)