Legal deadlines are expressions, not dates: modelling crypto licensing clocks in Python
Japan, Brazil, Kenya and Taiwan count time differently. Store the rule and the anchor, not just the answer
Most compliance trackers store a deadline as a date column. That works until a regulator writes "within 21 months after the date of commencement" and nobody has fixed the commencement date yet. Then someone types a guess into the column, the guess spreads into dashboards and newsletters, and six months later nobody remembers it was a guess.
At VASP Tracker we follow crypto licensing transitions in several countries. This post shows the small model we use instead: a deadline is an anchor (the legal event the clock starts from) plus a rule (how the text counts), and the date is something you compute, or refuse to compute.
Four ways to count
Here are four real clocks, all live or recently live in November 2026.
Japan. The 2026 amendment that moves crypto into the Financial Instruments and Exchange Act has a two-speed start. Its supplementary provisions say the Act takes effect on a date set by Cabinet Order "within a range not exceeding one year counted from the day of promulgation", while some provisions start on "the day on which 20 days have elapsed counted from the day of promulgation". The FSA gives 12 August 2026 for the early provisions (higher penalties for unregistered business and criminal investigation powers for the Securities and Exchange Surveillance Commission). Working back with the 20-day rule puts promulgation on 23 July 2026, and the one-year ceiling for the main provisions on 22 July 2027. That last date is our calculation, not an announced date. The Cabinet Order has not been published.
Brazil. Central bank Resolution BCB 520 took effect on 2 February 2026 and gave crypto firms already operating 270 days to apply for authorisation. That clock ran out on 30 October 2026. Firms that did not apply must stop within 30 days after the deadline (art. 88, para. 7), which we read as 29 November 2026.
Kenya. Section 47 of the Virtual Asset Service Providers Act says any person providing virtual asset services at commencement shall comply with the Act "within one year of the commencement". The Central Bank of Kenya says the Act became effective on 4 November 2025. We use 4 November 2026 as the end of the window.
Taiwan. Article 55 of the Virtual Asset Service Act gives existing registered firms 12 months after commencement to apply and 21 months to be licensed, with one extension of up to 3 months "where necessary". Article 56 leaves commencement to the Executive Yuan. As of 3 November 2026 the national laws database still lists the Act's effective date as "undetermined".
Four clocks, four counting styles: "days elapsed counted from", "N days", "within one year of", and "N months after" a date that does not exist yet.
The model
from __future__ import annotations
from dataclasses import dataclass
from datetime import date, timedelta
from typing import Callable, Optional
def add_months(d: date, n: int) -> date:
y, m = divmod(d.month - 1 + n, 12)
y, m = d.year + y, m + 1
for day in (d.day, 30, 29, 28): # clamp 31 Jan + 1 month etc.
try:
return date(y, m, day)
except ValueError:
pass
@dataclass
class Anchor:
name: str
value: Optional[date] # None = not fixed yet
source: str
@dataclass
class Deadline:
label: str
anchor: Anchor
rule: Callable[[date], date] # how the legal text counts
rule_text: str # the words we are modelling
kind: str = "latest" # "exact" or "latest" (a ceiling, not a date)
def resolve(self) -> str:
if self.anchor.value is None:
return f"PENDING ({self.rule_text}; waiting for: {self.anchor.name})"
d = self.rule(self.anchor.value)
tag = "on" if self.kind == "exact" else "no later than"
return f"{tag} {d.isoformat()} ({self.rule_text})"
And the data:
jp_prom = Anchor("Japan FIEA/PSA amendment promulgation", date(2026, 7, 23), "derived, see text")
br_res520 = Anchor("Resolucao BCB 520 in force", date(2026, 2, 2), "BCB")
br_deadline = Anchor("Brazil filing deadline", date(2026, 10, 30), "BCB")
ke_start = Anchor("Kenya VASP Act commencement", date(2025, 11, 4), "CBK notice")
tw_start = Anchor("Taiwan VASA commencement (Executive Yuan)", None, "art. 56")
deadlines = [
Deadline("JP early provisions", jp_prom, lambda d: d + timedelta(days=20),
"day on which 20 days have elapsed, counted from promulgation", "exact"),
Deadline("JP main provisions", jp_prom, lambda d: add_months(d, 12) - timedelta(days=1),
"Cabinet Order date within 1 year counted from promulgation"),
Deadline("BR incumbents apply", br_res520, lambda d: d + timedelta(days=270),
"270 days", "exact"),
Deadline("BR non-filers stop", br_deadline, lambda d: d + timedelta(days=30),
"within 30 days after the deadline"),
Deadline("KE comply", ke_start, lambda d: add_months(d, 12),
"within one year of commencement"),
Deadline("TW apply", tw_start, lambda d: add_months(d, 12),
"within 12 months after commencement"),
Deadline("TW licensed", tw_start, lambda d: add_months(d, 21),
"within 21 months after commencement"),
Deadline("TW licensed, extended", tw_start, lambda d: add_months(d, 24),
"21 months + one 3-month extension, if granted"),
]
for dl in deadlines:
print(f"{dl.label:<24} {dl.resolve()}")
Output:
JP early provisions on 2026-08-12 (day on which 20 days have elapsed, counted from promulgation)
JP main provisions no later than 2027-07-22 (Cabinet Order date within 1 year counted from promulgation)
BR incumbents apply on 2026-10-30 (270 days)
BR non-filers stop no later than 2026-11-29 (within 30 days after the deadline)
KE comply no later than 2026-11-04 (within one year of commencement)
TW apply PENDING (within 12 months after commencement; waiting for: Taiwan VASA commencement (Executive Yuan))
TW licensed PENDING (within 21 months after commencement; waiting for: Taiwan VASA commencement (Executive Yuan))
TW licensed, extended PENDING (21 months + one 3-month extension, if granted; waiting for: Taiwan VASA commencement (Executive Yuan))
What the model buys you
Unknown stays unknown. Taiwan prints PENDING, not a date. The day the Executive Yuan publishes a commencement order, you change one Anchor.value and every dependent deadline appears at once, with the rule text still attached. VASP Tracker's Taiwan timeline works the same way: the transition rows wait for commencement.
Ceilings are not dates. Japan's 22 July 2027 is the latest the Cabinet Order can choose, not the date it will choose. The kind field keeps "on" and "no later than" apart, so a dashboard cannot quietly turn a ceiling into a launch date.
Counting conventions are visible. The Japanese "20 days elapsed counted from promulgation" and the Brazilian "270 days" happen to land on plain + timedelta(days=N) here, but they are different phrases and they will not always agree. "Within one year of" is worse: you could argue for 3 November or 4 November in Kenya. We use 4 November, as in our Kenya deadline explainer. The point is not that our reading is the only one. It is that the reading lives in one lambda, next to the words it models, where a lawyer can check it.
Derived anchors are labelled. Japan's promulgation date is derived from the 12 August effective date, not read from a gazette. The source field says so. When a primary source turns up, swap it in and nothing downstream changes.
Things we deliberately left out
- Business-day and holiday rules. None of the four clocks above use them, so we did not build them. Add them per jurisdiction when a text actually says "business days".
- Time zones. A deadline "date" is a calendar day in the regulator's jurisdiction. If you store timestamps, store the zone, or 30 October in Brasilia becomes 31 October in Shanghai.
- Extensions as dates. Taiwan's extension is discretionary and per firm. We model it as a separate ceiling, never as the main deadline.
Takeaway
Store the anchor, the rule and the source text. Compute the date. Print "pending" when the law says the date is not set. It is a few dozen lines of Python and it removes a whole class of confident, wrong dates.
This is not legal advice. The dates above are VASP Tracker's reading of the official texts as of 3 November 2026; the regulators' own publications prevail.
VASP Tracker is an independent tracker. It is not an official source and is not affiliated with any regulator.
Daniel Bradley, VASP Tracker
About the author
- Independent tracker of when crypto firms must be licensed in 74 jurisdictions. Every date linked to the law or regulator. Open data, CC BY 4.0.
Comments
Join the discussionNo comments yet. Be the first to comment.