Check a release's time, period and previous value before it comes out

Read the economic calendar for one country, keep the releases whose topic you trade and sort them by the at timestamp. Each entry gives the release time in UTC, the publisher's time zone, the period the figures cover and the previous value of each measure, so a trader sees what is due and what it will be compared with.

Look up one release for one country

Ask the calendar for a country and a day with GET /v1/economics/calendar. This request asks for Japan on 20 November.

curl, Japan's calendar for one day
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
  "https://api.narwhalapi.com/v1/economics/calendar?countries=JPN&start_date=2026-11-20&end_date=2026-11-20&limit=100"
Response
{
  "releases": [
    {
      "release_id": "6c00d274-da35-4ed4-bcc1-574101544a03",
      "revision": 3,
      "country": "JPN",
      "series_id": "jpn-consumer-prices",
      "name": "Consumer prices",
      "topic": "consumer_prices",
      "family": "prices",
      "period": "2026-10",
      "status": "scheduled",
      "at": "2026-11-19T23:30:00Z",
      "timezone": "Asia/Tokyo",
      "values": [
        {
          "measure": "core_core_cpi_yoy",
          "concept": "cpi_ex_fresh_food_energy",
          "unit": "percent",
          "transformation": "year_over_year",
          "previous": "2.4",
          "not_seasonally_adjusted": true
        },
        {
          "measure": "core_cpi_yoy",
          "concept": "cpi_ex_fresh_food",
          "unit": "percent",
          "transformation": "year_over_year",
          "previous": "2.1",
          "not_seasonally_adjusted": true
        },
        {
          "measure": "cpi_mom",
          "concept": "cpi",
          "unit": "percent",
          "transformation": "month_over_month",
          "previous": "0.4"
        },
        {
          "measure": "cpi_yoy",
          "concept": "cpi",
          "unit": "percent",
          "transformation": "year_over_year",
          "previous": "2.1",
          "not_seasonally_adjusted": true
        }
      ]
    }
  ],
  "next_cursor": null
}

The release is Japan's consumer prices for period 2026-10, so the figures cover October. at is 2026-11-19T23:30:00Z and timezone is Asia/Tokyo. Each item in values has a measure and a previous value; the previous cpi_yoy is 2.1 and the previous cpi_mom is 0.4. The figures are strings, so convert them to numbers before comparing.

transformation says how a figure is derived: year_over_year for cpi_yoy and month_over_month for cpi_mom. Three of the four measures carry not_seasonally_adjusted: true, so check the flag before you compare a forecast with the previous figure.

The request asked for 20 November, yet at falls on 19 November in UTC. The date window follows the publisher's local calendar, and 23:30 UTC is 08:30 the next morning in Tokyo.

Pick the next high-interest releases and convert the time

The calendar has no importance rating, so you decide what counts as high interest. The script below uses a watch list of topic values, keeps releases that are still scheduled and have an at time, sorts them and takes the first three.

  1. Set the watch list and your own zone Put the topics you trade in a set. The script watches consumer prices, GDP, labour force, employment and wages, and converts to America/New_York as the trader's zone.
  2. Request the window Ask for one country and a range of dates. The script uses Japan from 16 to 29 November with limit 100.
  3. Filter, sort and convert datetime.fromisoformat reads the UTC timestamp. astimezone converts it to the publisher's zone from the timezone field and to the trader's zone. The previous values come from values[].previous.
    Python, the next three watched releases
    import os
    from datetime import datetime
    from zoneinfo import ZoneInfo
    import requests
    
    BASE = "https://api.narwhalapi.com"
    
    WATCH = {"consumer_prices", "gdp", "labour_force", "employment", "wages"}
    MY_TZ = ZoneInfo("America/New_York")
    
    r = requests.get(
        f"{BASE}/v1/economics/calendar",
        params={"countries": "JPN", "start_date": "2026-11-16", "end_date": "2026-11-29", "limit": 100},
        headers={"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"},
        timeout=10,
    )
    r.raise_for_status()
    
    picked = [
        x for x in r.json()["releases"]
        if x.get("topic") in WATCH and x["status"] == "scheduled" and "at" in x
    ]
    for x in sorted(picked, key=lambda x: x["at"])[:3]:
        utc = datetime.fromisoformat(x["at"].replace("Z", "+00:00"))
        local = utc.astimezone(ZoneInfo(x["timezone"]))
        mine = utc.astimezone(MY_TZ)
        prev = ", ".join(f"{v['measure']} {v['previous']}" for v in x["values"] if "previous" in v)
        print(x["name"], x["period"])
        print("  UTC  ", utc.strftime("%a %d %b %H:%M"))
        print("  Tokyo", local.strftime("%a %d %b %H:%M"))
        print("  NYC  ", mine.strftime("%a %d %b %H:%M"))
        print("  previous:", prev or "none listed")
Output of the script
GDP 2026-Q3
  UTC   Sun 15 Nov 23:50
  Tokyo Mon 16 Nov 08:50
  NYC   Sun 15 Nov 18:50
  previous: none listed
Consumer prices 2026-10
  UTC   Thu 19 Nov 23:30
  Tokyo Fri 20 Nov 08:30
  NYC   Thu 19 Nov 18:30
  previous: core_core_cpi_yoy 2.4, core_cpi_yoy 2.1, cpi_mom 0.4, cpi_yoy 2.1
Wages and earnings 2026-09
  UTC   Tue 24 Nov 23:30
  Tokyo Wed 25 Nov 08:30
  NYC   Tue 24 Nov 18:30
  previous: average_cash_earnings_yoy 3.9, real_wages_yoy 1.6

The GDP row shows Sun 15 Nov 23:50 in UTC although the window began on 16 November, because it is 08:50 on Monday 16 November in Tokyo. Its previous line reads none listed, since this GDP release has an empty values list. The script prints a placeholder whenever no previous exists, so one missing figure does not stop the loop.

One moment in three clocks

ClockConsumer prices releaseHow it is derived
UTCThu 19 Nov 23:30The at value
TokyoFri 20 Nov 08:30at converted to the timezone field, Asia/Tokyo
New YorkThu 19 Nov 18:30at converted to the trader's zone

Tokyo is nine hours ahead of UTC, and 23:30 plus nine hours is 08:30 the next day. New York is five hours behind UTC on that date, so 23:30 minus five hours is 18:30. The script uses zoneinfo, which applies daylight saving rules by itself, so you do not store offsets.

Read the same release again later

Every release has a release_id. GET /v1/economics/calendar/{release_id} returns that one release with two extra fields, version and observed_at, which says when Narwhal last saw the release in the publisher's calendar. Use it to refresh the row for a release you are watching without downloading the whole window.

status moves from scheduled to published when the figures are out, and a value can then carry actual beside previous. Some releases also have a stage, such as flash, advance, preliminary or final. Show it next to the name so a first estimate is not mistaken for the final one.

Does the calendar rank releases by importance?

No. Releases carry a family such as prices, labour or gdp, and a topic such as consumer_prices, but no rating. Build the watch list from those two fields, and use .get("topic") because some releases have no topic.

Why do some releases have no previous value?

values is always present and can be an empty list, and a measure can lack previous. The Japan GDP release above has an empty list. When a release revises the earlier number, previous_revised_from holds the figure it replaced.

What if a release has no exact time?

It has no at. It carries date, between or by instead, which the script skips because it needs a timestamp to convert. If you also want those rows, print the date and mark the time as unknown rather than guessing one.

Published .

Next steps