Our server changes its date at Coordinated Universal Time. Jakarta is 7 hours ahead of that. So from midnight until 7 in the morning here, the previous day is still running inside the server. Anything recorded during those 7 hours was today to the person recording it, and yesterday inside our software.
E found it. He lives in a small town some way outside Jakarta and starts his day early. At 6:40 in the morning on 11 August he went to enter 1 journal entry in KAZENA Books on his own device, and saw the previous day's date already filled into the date field. He sent a screen recording. He retyped the date, saved, and then asked whether the clock on his device was wrong. His device was not the thing that was wrong.
Here is the mechanism. The default date on a journal entry was built from the server's current time. The stamp we write when saving came from the same time. And the range our daily sales summary calls today came from there as well. It was not 3 places each making their own mistake; it was 3 places sharing one source. The source was not the problem. Turning it into a calendar date was.
We counted. Of the entries created between 1 June and 20 August, 613 were created between midnight and 7 in the morning in the local time of the person creating them. Of those, 488 were saved without anyone correcting the date field by hand. Those 488 carry a date in the ledger 1 day earlier than the day they happened.
Nineteen of them crossed a month boundary. A transaction recorded in the early hours of the 1st sits in the previous month's totals, 31,400,000 rupiah in all. The yearly total does not change; the monthly ones do. Anyone reading their statements month by month was seeing a lighter August and a heavier July.
It is worth writing down why nobody reported it. The date field can be edited. A person who thinks it looks wrong retypes it and saves. A defect you can fix on the spot never gets reported as a defect, because you assume you mistyped it. A bug the user can blame on themselves will never reach us.
Those 7 hours are not quiet hours in this city. The street near the office is moving before 5, and there is already a line at the bubur ayam cart. Some warungs never close at all. What we were treating as still yesterday was, for a great many small businesses, the busiest stretch of their day.
There was a deeper mistake underneath it. We were deriving the time zone from the country. Indonesia has 3 of them: Jakarta is WIB at +7, Makassar is WITA at +8, Jayapura is WIT at +9. By reading the country setting and deciding on +7, we were handing users on the eastern islands a further 1 or 2 hours of error.
I will not defend it. Storing time in UTC is not the wrong idea. What I got wrong came after that. An instant and a calendar date are different things. An instant is the same everywhere in the world; a calendar day depends on where the person looking at it is standing. I called both of them the date and kept them in the same drawer.
The tests passed. Our automated tests ran around noon UTC, an hour that falls on the same calendar day seen from any of the countries we serve. We were checking the boundary from a place that never crossed it. The clock is pinned now: 23:50, 00:10 and 6:59, run across the 5 time zones we serve. That is 15 combinations, every time.
Here is the fix. A ledger now carries its own time zone. The country only proposes the initial value, and it can be changed in the settings at any time. The default date on an entry, and the ranges behind the daily and monthly summaries, are built from the calendar day in that zone. The saved stamp stays in UTC, because ordering and the audit trail need it there. Only the date we show a person moved to that person's side.
We have not rewritten a single one of the 488 entries already saved. The date field is an editable field. Whatever sits in it is ultimately the date that person put there, not something for us to guess at and overwrite. For the 19 that crossed a month we did get in touch, with the list of what is affected and the steps to correct it. Whether to correct it is theirs to decide.
One thing I should say plainly. I am not a tax accountant. The date on a transaction decides which filing period it belongs to, and a 1-day difference that crosses a month changes the month being filed. If any of this sounds familiar, check what you recorded in the early hours at the start of a month. Please confirm anything final with a professional.
These days, whenever the word today appears in our code, I stop once and ask whose today it is. A server does not have a today. It only has an instant. The one holding a today is the person in front of the screen. If a date anywhere in KAZENA is a day off from what you expected, tell us. Your clock is probably fine.
Tell us what you think
How the KAZENA apps feel to use, what we should fix, features you wish existed — if you run a small or medium business or work freelance in Indonesia or the Philippines, your voice is exactly what we want to hear. Messages in Bahasa Indonesia or English are answered by teammates who know your market from the inside. KAZENA Books is already set to launch in the Philippines and Indonesia — and if your company would like to bring it to other countries as a partner, or is interested in acquiring the system, we would love to hear from you too. We also take on new system development. We are a small team, so we cannot always start right away — but what we build carries made-in-Japan quality and stays close to how business really works here, one project at a time.
Get in touch