Skip to content

Dates and Ranges

Markwhen supports a variety of date formats and mechanisms for expressing periods of time.

When parsing, EDTF takes precedence over other date formats mentioned here. So if there is some ambiguity in how a date range is expressed, and it fits the EDTF range format, it will be parsed as EDTF.

Every event has an associated date range, whether it has an explicitly written end date or not. A date range is a period from one date to another.

EDTF Date Ranges

Extended Date Time Format

Markwhen is currently level 0 EDTF compliant, supporting ranges such as:

1964/2008
2004-06 / 2006-08
2004-02-01/ 2005-02-08
2004-02-01 /2005-02
2004-02-01/2005
2005/2006-02
2005/now
2018/6 months

Open-ended ranges are not supported.

Ranges start and end with either a EDTF Date or Relative Date or the special keyword now.

EDTF Date

Essentially the first part of a full ISO8601 date, whose regex could be expressed as \d{4}(-\d{2}(-\d{2})?)?:

1981
2012-05
2022-01-30

Non-EDTF Date Ranges

Many other expressions of dates are supported by markwhen, not just EDTF. A date range is typically Date[-Date]; that is, one date optionally followed by a dash (-) or the word to and another date.

If an end date is not specified, the range is as long as its granularity. For example, the event

2001: A Space Odyssey

starts January 1, 2001, and lasts through December 31, 2001.

ExampleInferred RangeExplanation
20242024-01-01T00:00:00Z to 2025-01-01T00:00:00ZFrom the start of 2024 to the end of 2024
04/17761776-04-01T00:00:00Z to 1776-05-01T00:00:00ZFrom the start of April 1776 to the end of April 1776
01/01/20242024-01-01T00:00:00Z to 2024-01-02T00:00:00ZFrom the start of January 1, 2024, to the end of January 1, 2024 (the whole day).
11/11/2024-12/12/20242024-11-11T00:00:00Z to 2024-12-13T00:00:00ZFrom the start of November 11, 2024, to the end of December 12, 2024.
2031-11-19T01:35:10Z-2099-08-04T18:22:48Z2031-11-19T01:35:10Z to 2099-08-04T18:22:48ZExactly as specific as the ISO dates say.
January 3 - Apr 62022-01-01T00:00:00Z to 2022-04-07T00:00:00ZAs this documentation was written in 2022, the year 2022 is inferred. Note how the range extends to the end or April 6, which makes it the beginning of April 7.
now - 10 years 6 months 3 daysnow to 10 years, 6 months, and 3 days laternow is whatever time the timeline is rendered, not when it was written. 10 years 6 months 3 days is a relative date.
3:30pm - 4:30pmToday's date, from 15:30 to 16:30When a time is by itself, it is based off of the last date seen, or, if there isn't any, today.
1 Jan 1998 to 11/11/2011 8am1998-01-01T00:00:00Z to 2011-11-11T08:00:00Z
Nov 11 02:302011-11-11T02:30:00Z to 2011-11-11T02:30:00ZWhen a time is specified (hour/minute), the granularity is instant.

Non-EDTF Dates

A date can be expressed in a few forms. Human readable dates are supported, like 1665, 03/2222, 09/11/2001, 18 March 2026, Aug 30 9:45am, as well as IO8601 dates, like 2031-11-19T01:35:10Z. Human readable date formatting defaults to the American Month/Day/Year but can be changed to European formatting via the header.

Relative Dates

If you have events that are based off of, or relative to, other events, you can describe their relationship to get the range you want.

For example, say you are working on a project tracker. You could outline the phases of your project by using absolute dates, like the following:

// To indicate we are using European date formatting
dateFormat: d/M/y

// 2 weeks
01/01/2023 - 14/01/2023: Phase 1 #Exploratory

// Another 2 weeks
15/01/2023 - 31/01/2023: Phase 2 #Implementation

// 1 month
02/2023: Phase 3 #Implementation

// 3 days, after a one week buffer
07/03/2023 - 10/03/2023: Phase 4 - kickoff! #Launch

However, as soon as something changes (say something slips or an estimate was wrong), you would have to go through all events and change their dates manually. This would be especially troublesome if the change is early on.

With relative dates, we can express the same timeline like so:

// 2 weeks
01/01/2023 - 2 weeks: Phase 1 #Exploratory

// Another 2 weeks
2 weeks: Phase 2 #Implementation

// 1 month
1 month: Phase 3 #Implementation

// One week after phase 3 ends, a 3 days kickoff event
1 week - 3 days: Phase 4 - kickoff! #Launch

Relative dates base themselves off the previous date, and this goes all the way back to our first date, 01/01/2023.

Event IDs

This works well enough for serial dates that are each dependent on the last, but what if we have multiple events that are all dependent on the same event? We can do that using event ids:

// Event ids are represented by an exclamation point followed
// by the id - like !Phase1
01/01/2023 - 2 weeks: Phase 1 #Exploratory !Phase1

// Another 2 weeks
after !Phase1 2 weeks: Phase 2, in parallel with Phase 3 #Implementation

// 1 month
after !Phase1 1 month: Phase 3, in parallel with Phase 2 #Implementation

// 3 days, after a one week buffer
1 week - 3 days: Phase 4 - kickoff! #Launch

The word after is optional, we could say !Phase1 2 weeks: Phase 2, in parallel with Phase 3 #Implementation to have the same effect.

Relative dates will first attempt to refer to the event that was specified by a provided event id. For !Phase1 2 weeks: Phase 2, the event with the id Phase1 is looked for, is checked for when it ends, and is used as the reference upon which 2 weeks is based.

If we can't find the event id, or no event id is given, the relative date is instead based upon the last date in the timeline - "last" here meaning most recently written, as the timeline is parsed from top to bottom. So if we have a timeline like this:

2020: Pandemic
2021 - 2023: More pandemic
1 year: Less pandemic?

1 year is based off the last date seen, which would be 2023, or, more specifically, the end of 2023.

This also means that we can base our end date off of our start date:

12/25/2022: Christmas
5 days - 3 days: New Years' stuff

Here, 5 days is five days after the previously seen date (12/25/2022), which would make it 12/30/2022, while 3 days is three days after the previous date, which is our start date of 12/30/2022.

Two relative dates together, like x days - y weeks: ..., can therefore essentially be read as x days after the previous event and lasts for y weeks.

The only exception to this is the shorthand singular relative date, like x years:..., which means immediately after the last event and lasts for x years.

Due dates

In the same way you can represent an event taking place after a prior event, you can indicate that an event should come before another. Let's say we wanted to get some things done before Christmas:

2022-12-25: Christmas !Christmas
before !Christmas 1 month: Buy presents
before !Christmas 2 weeks: Get a tree

By using event ids, we specify the due date, and specify the amount of time before that event. Like all event ids, the id must be defined earlier in the document in order to be able to reference it; something like the following would not work:

before !Christmas 1 month: Buy presents
before !Christmas 2 weeks: Get a tree
2022-12-25: Christmas !Christmas

because the event with the id of !Christmas is after the events that refer to it. A good way to deal with this is to define the known dates at the start of your timeline and then look at a sorted view to see them in order.

Similar to relative events that are dependent on preceding events, events with due dates can also have start and end times:

2022-12-25: Christmas !Christmas
before !Christmas 1 week - 1 month: Buy presents

Here, the Buy presents event ends 1 week before Christmas, and lasts for 1 month. When dealing with relative events, the first part of the range (if there is one) can be considered the "buffer," while the second part is the duration. If there is only one part (no range; before !Christmas 1 month instead of before !Christmas 1 week - 1 month), then it will abut the event it is basing itself off of with the specified duration.

Also similarly to other relative events, if no event id is specified, it will be dependent on the previous event.

Before and by can both be used to represent happening before another event. These are equivalent:

by !Chistmas 1 day: ...
before !Christmas 1 day: ...

Week days

When using relative dates you can also take advantage of being able to specify week days - this calculates durations based on how many non-weekend days it takes.

For example:

July 13, 2022 - 5 week days: Item estimate
10 week days: Second part of item

July 13, 2022 is a Wednesday, and we're counting 5 week days, so we go Wednesday, Thursday, Friday (3), and then the following Monday and Tuesday (2), which gets us to the end of July 19 (technically midnight July 20, a Wednesday).

The second event starts after the first and lasts 10 weekdays, which would take us to two Wednesdays into the future, or 14 calendar days.

Week, work, and business are supported as prefixes to day when working with weekdays. These are all equivalent:

10 business days: ...
10 weekdays: ...
10 work days: ...

Week days do not take into account holidays - only weekends. It also assumes a 5 day work week, unfortunately. Hopefully soon it will be 4 days.

Recurring events

To have an event repeat itself some number of times, you can use recurrence syntax between the event range and the event description:

October 7, 1989 every year for 10 years: ...
2025-03-04 every week for 12 weeks: ...
2022-01/2022-03 every other year x9: ...
Feb 1 2023 every 6 months for 10 times: ...

Recurrence syntax essentially takes the form of

every (duration) (for (number of times | duration)) | x(amount)