# Days, weeks and months in a time zone — at.Bucket(TimeBucket.Month, zone)

> The start of the hour, day, week, month, quarter or year an instant falls in — counted on a team's own clock, so a day starts at midnight in Stockholm, the month of March ends when Stockholm's March does (summer time included), and a week starts on the day you say. Grouped by in the database (`date_trunc` at the zone), or over a list in memory, with the same answer.

<!-- id: query-time-buckets · area: query · stability: preview · html: https://osysharp.com/reference/query/time-buckets/ -->

## Summary        {#summary}
Group by the month (or day, or week) in the zone the team works in:

```osy title="jobs per month, on Stockholm's calendar" test app=query-time-buckets
class PerMonth {
  public DateTime Month;
  public int Jobs;
}

entity Job {
  [Required, MaxLength(20)] string Team;
  DateTime At;
}

List<PerMonth> Monthly() {
  var stockholm = TimeZoneInfo.FindSystemTimeZoneById("Europe/Stockholm");
  return Job.GroupBy(j => j.At.Bucket(TimeBucket.Month, stockholm))
            .Select(g => new PerMonth { Month = g.Key, Jobs = g.Count() })
            .OrderBy(m => m.Month)
            .ToList();
}

List<PerMonth> WeeklyFromSunday() {
  var stockholm = TimeZoneInfo.FindSystemTimeZoneById("Europe/Stockholm");
  return Job.GroupBy(j => j.At.Bucket(TimeBucket.Week, stockholm, DayOfWeek.Sunday))
            .Select(g => new PerMonth { Month = g.Key, Jobs = g.Count() })
            .OrderBy(m => m.Month)
            .ToList();
}
```

A job at 22:30 UTC on 31 March is in April in Stockholm (00:30 on 1 April, summer time), and is counted there.

## Signature      {#signature}
```osy syntax
DateTime Bucket(this DateTime at, TimeBucket unit, TimeZoneInfo zone)
DateTime Bucket(this DateTime at, TimeBucket unit, TimeZoneInfo zone, DayOfWeek weekStart)   // a week from this day
public enum TimeBucket { Hour, Day, Week, Month, Quarter, Year }
```
The answer is an instant (UTC): the moment the bucket starts in `zone`. Two instants share a bucket exactly when they
fall in the same local hour, day, week, month, quarter or year there.

## Description    {#description}

### A calendar, not a clock   {#calendar}
A day in Stockholm is 23 hours on the last Sunday of March and 25 on the last Sunday of October; a bucket follows the
calendar, so each day is one bar and none is split. Counting in UTC instead moves every evening's work after 22:00 (or
23:00 in winter) into the next day.

### Weeks start on the day you say   {#weeks}
Without a `weekStart` a week starts on Monday (ISO). `DayOfWeek.Sunday` or `DayOfWeek.Saturday` starts it there.

### Same answer in memory   {#in-memory}
`list.GroupBy(j => j.At.Bucket(TimeBucket.Month, zone))` over a `List<T>` gives the same buckets, so a test over a list
and a report over the table agree.

## See also       {#see-also}
- [GroupBy (and HAVING)](https://osysharp.com/reference/query/group-by/) — grouping and HAVING.
- [Median and percentiles — g.Median(…), g.Percentile(…, 0.9)](https://osysharp.com/reference/query/percentiles/) — medians and percentiles per bucket.
- [Time zones — TimeZoneInfo](https://osysharp.com/reference/stdlib/zones/) — `Zone.Of`, and instants in a zone.
