55

I am using PostgreSQL 8.3. I have a table like this:

id        regist_time        result
-----------------------------------
1     2012-07-09 15:00:08      3
2     2012-07-25 22:24:22      7
4     2012-07-07 22:24:22      8

regist_time's data type is timestamp.

I need to find a week time interval(start to end) and sum(result) as num.

I want to get the result as:

      week                    num    
---------------------------------
7/1/2012-7/7/2012              10
7/8/2012-7/14/2012              5
7/15/2012-7/21/2012             3
7/22/2012-7/28/2012            11

I can get the week number just in this year:

SELECT id,regis_time, EXTRACT(WEEK FROM regis_time) AS regweek
FROM tba

The key part is

EXTRACT(WEEK FROM regis_time) 

extract function can only get the week number in this year, how can I get start time to end time in one week?

6 Answers 6

122

You can use date_trunc('week', ...).

For example:

SELECT date_trunc('week', '2012-07-25 22:24:22'::timestamp);
-> 2012-07-23 00:00:00

Then, you can convert this into a date, if you're not interested in a start time.

To get the end date too:

SELECT    date_trunc('week', '2012-07-25 22:24:22'::timestamp)::date
   || ' '
   || (date_trunc('week', '2012-07-25 22:24:22'::timestamp)+ '6 days'::interval)::date;

-> 2012-07-23 2012-07-29

(I've used the default formatting here, you can of course adapt this to use MM/DD/YYYY.)

Note that, if you want to make comparisons on timestamps, instead of using (date_trunc('week', ...) + '6 days'::interval, you might want to add an entire week and use a strict comparison for the end of the week.

This will exclude y timestamps on the last day of the week (since the cut-off time is midnight on the day).

    date_trunc('week', x)::date <= y::timestamp
AND y::timestamp <= (date_trunc('week', x) + '6 days'::interval)::date

This will include them:

    date_trunc('week', x)::date <= y::timestamp
AND y::timestamp < (date_trunc('week', x) + '1 week'::interval)

(That's in the rare cases when you can't use date_trunc on y directly.)


If your week starts on a Sunday, replacing date_trunc('week', x)::date with date_trunc('week', x + '1 day'::interval)::date - '1 day'::interval should work.

Sign up to request clarification or add additional context in comments.

2 Comments

This assumes that weeks start on Monday. Is there a way to do the same thing but with weeks that start on a Sunday?
Thanks! Sorry, I'm not using SO very often. Upvoted! :D
18
select date_trunc('week', regist_time)::date || ' - ' ||
       (date_trunc('week', regist_time) + '6 days') ::date as Week,
       sum(result) Total
from YourTable
group by date_trunc('week', regist_time)
order by date_trunc('week', regist_time)

See proof of concept at SQLFiddle: http://sqlfiddle.com/#!1/9e821/1

Comments

5

This can help, a query to get all days of current week.

select cast(date_trunc('week', current_date) as date) + i
from generate_series(0,6) i

2015-08-17
2015-08-18
2015-08-19
2015-08-20
2015-08-21

To get week start and end date (as 0 for Monday and 4 for Friday):

select cast(date_trunc('week', current_date) as date) + 0 || '-->' ||  cast(date_trunc('week', current_date) as date) + 4;

2015-08-17-->2015-08-21

Comments

4

It is

select to_date('2015-07', 'IYYY-IW');

use it in postgres

it will return

2015-02-09

Comments

0

If you want to get week start and end date with week start day is any day in the week (Monday, Tuesday, ...). You can use this way:

day_of_week_index mapping:

{
    'monday': 1,
    'tuesday': 2,
    'wednesday': 3,
    'thursday': 4,
    'friday': 5,
    'saturday': 6,
    'sunday': 7
}

Query template:

SELECT 
concat(
    CASE
        WHEN extract(ISODOW FROM datetime_column) < day_of_week_index THEN cast(date_trunc('week', datetime_column) AS date) - 8 + day_of_week_index
        ELSE cast(date_trunc('week', datetime_column) AS date) - 1 + day_of_week_index
    END, ' - ', 
    CASE
        WHEN extract(ISODOW FROM datetime_column) < day_of_week_index THEN cast(date_trunc('week', datetime_column) AS date) - 8 + day_of_week_index + 6
        ELSE cast(date_trunc('week', datetime_column) AS date) - 1 + day_of_week_index + 6
    END) 
FROM table_name;

Example:

Get week start and end date with week start day is Tuesday:

SELECT 
concat(
    CASE
        WHEN extract(ISODOW FROM TIMESTAMP '2021-12-01 03:00:00') < 2 THEN cast(date_trunc('week', TIMESTAMP '2021-12-01 03:00:00') AS date) - 8 + 2
        ELSE cast(date_trunc('week', TIMESTAMP '2021-12-01 03:00:00') AS date) - 1 + 2
    END, ' - ', 
    CASE
        WHEN extract(ISODOW FROM TIMESTAMP '2021-12-01 03:00:00') < 2 THEN cast(date_trunc('week', TIMESTAMP '2021-12-01 03:00:00') AS date) - 8 + 2 + 6
        ELSE cast(date_trunc('week', TIMESTAMP '2021-12-01 03:00:00') AS date) - 1 + 2 + 6
    END);

=> Result:

2021-11-30 - 2021-12-06

Note: You can change the day_of_week_index following the above mapping to determine the week start day (Monday, Tuesday, ..., Sunday)

Comments

0

To get the start of the week as a date:

SELECT CAST(date_trunc('week', CURRENT_DATE) AS DATE);

To get the end of the week as a date:

SELECT CAST(date_trunc('week', CURRENT_DATE) AS DATE) + 5;

You can always play around with the query by adding integers that represent the days to the end.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.