Japanese Era (Wareki) Date Cells in C# — Display 令和8年6月6日 While the Data Stays a DateTime

· unvell team
Japanese Era (Wareki) Date Cells in C# — Display 令和8年6月6日 While the Data Stays a DateTime

If you build software for Japanese businesses — or maintain a product that just landed its first Japanese customer — sooner or later this requirement arrives: invoice dates, contract dates, birthdates, and anything submitted to a government office must be shown in wareki (和暦), the Japanese era calendar. Not 2026-06-06, but 令和8年6月6日 — “Reiwa year 8, June 6”.

A quick primer if this is new to you: Japan numbers years by imperial era. The current era is Reiwa (令和), which began on May 1, 2019 — so 2026 is Reiwa 8. Before that came Heisei (平成, 1989–2019**)** and Showa (昭和, 1926–1989**)**. The year count resets to 1 at every transition, and official documents still use this calendar every day. “Can’t we just use the Western calendar?” is a negotiation you will usually lose.

And most implementations stumble on the very first step: they turn the date into a string.

This article shows how to keep cell data as a real DateTime and make only the display wareki. The examples use ReoGrid, because switching to the Japanese era calendar is built into its data-format engine.


The usual implementation, and what it costs

The most natural-looking approach is to build a wareki culture and format the date into the cell:

var wareki = new CultureInfo("ja-JP");
wareki.DateTimeFormat.Calendar = new JapaneseCalendar();

sheet["B3"] = date.ToString("ggy年M月d日", wareki);   // ← stored as a string

The display looks right. But the cell no longer contains a date — it contains plain text. The bill arrives later, all at once:

  • Sorting breaks. String comparison puts 令和10年 (Reiwa 10) before 令和2年 (Reiwa 2), because it compares character by character. This is the classic wareki-string bug, and it surfaces the moment someone sorts the date column.
  • Formulas stop working. Date math like =DAYS(B3, TODAY()) errors out on a text cell. Every “days until the due date” calculation is gone.
  • Filtering fails. You can’t filter “April 2026 and later” against strings.
  • Changing the format means changing the data. When someone asks for Western dates alongside, you get to rebuild every cell.

The root cause is a single mistake: the display concern got baked into the data.


The right way: data stays DateTime, only the display is wareki

In ReoGrid, a cell’s value and its display format are separate. Give a date cell a wareki format and the data remains a DateTime — only what’s painted on screen changes.

using unvell.ReoGrid;
using unvell.ReoGrid.DataFormat;

var sheet = grid.CurrentWorksheet;

// Format column B as wareki dates
sheet.SetRangeDataFormat("B3:B100", CellDataFormatFlag.DateTime,
    new DateTimeDataFormatter.DateTimeFormatArgs
    {
        Format = "ggy年M月d日",   // gg = era name, y = year within the era
        CultureName = "ja-JP",
    });

sheet["B3"] = new DateTime(2026, 6, 6);   // displays: 令和8年6月6日

That’s the whole trick. The key is the gg (era) specifier in the pattern: when the culture is Japanese (ja) and the format contains g, ReoGrid automatically switches the calendar to .NET’s JapaneseCalendar. Era detection and year-within-era arithmetic are handled by the framework — you never hardcode an era transition table.

The pattern is a standard .NET date format pattern. Useful combinations:

PatternDisplays as
ggy年M月d日令和8年6月6日
ggy年M月d日(ddd)令和8年6月6日(土) — with the weekday
ggyy/MM/dd令和08/06/06
yyyy年M月d日 (no g)2026年6月6日 — stays Western

Drop the g and the same cell renders in the Western calendar again. The data was never touched, so toggling between wareki and Western display is a format swap, not a data migration. The “actually, can we show both?” request stops being scary.

Note: these are .NET patterns. Excel’s own format codes for wareki (ggge"年"m"月"d"日", where e is the era year) follow a different convention — in .NET, the era year is written with y / yy.


Users can keep typing Western dates

So what happens when a user types 2026/6/6 into a wareki-formatted cell?

When editing ends, ReoGrid parses strings entered into a DateTime-formatted cell with DateTime.TryParse and stores a real DateTime. The display then follows the cell’s format — wareki.

User types:     2026/6/6
Cell data:      DateTime (2026-06-06)
Cell displays:  令和8年6月6日

“Input in Western, display in wareki” — the standard requirement in Japanese business apps — works with zero extra code. Because the data is a DateTime, sorting and formulas are correct from the moment of entry:

sheet["C3"] = "=DAYS(B3, TODAY())";   // days until the contract date — works on wareki-displayed cells

ReoGrid’s built-in formula engine ships date functions like DAYS, TODAY, YEAR, and MONTH, and they compute directly against the cell’s DateTime data.


Showa and Heisei come free — use it on birthdate columns

JapaneseCalendar knows every era boundary. A column like customer birthdates, where three or four eras coexist, needs the format set exactly once:

sheet["B4"] = new DateTime(1980, 4, 2);    // 昭和55年4月2日   (Showa 55)
sheet["B5"] = new DateTime(1989, 1, 7);    // 昭和64年1月7日   (the last day of Showa)
sheet["B6"] = new DateTime(1989, 1, 8);    // 平成元年1月8日    (Heisei begins)
sheet["B7"] = new DateTime(2019, 4, 30);   // 平成31年4月30日  (the last day of Heisei)
sheet["B8"] = new DateTime(2019, 5, 1);    // 令和元年5月1日    (Reiwa begins)
A sheet whose column A holds Western dates and column B the same values displayed as 令和8年6月6日, 昭和55年4月2日, 昭和64年1月7日, 平成元年1月8日, 平成31年4月30日 and 令和元年5月1日
Result — the six dates above, with the wareki format applied to column B. Column A shows the DateTime still in the cell; the header row and column A are added for the picture.

One day either side of a transition renders correctly. If you’ve ever written the era-detection if chain by hand, you know what this is worth.


元年 — the first year of an era, already right

Formal Japanese documents write the first year of an era as 元年gannen, “the origin year” — never “year 1”. JapaneseCalendar already does that for you: the two transition rows above come out as 平成年1月8日 and 令和年5月1日 with no extra code.

That has been .NET’s default since the 2019 era update — verified here on both .NET Framework 4.8 and .NET 8. Excel is the one that needs asking: plain ggge gives you 令和1年, and the formal notation takes the [$-ja-JP-x-gannen] prefix.

So the default display is already the one a contract or an invoice wants.


Overriding the display: a custom formatter

The interesting case is the other direction — a counterpart system that will only accept 令和1年, an internal style guide, a column that mixes 和暦 and 西暦. ReoGrid’s custom data formatter is the hook: implement IDataFormatter and return whatever string the cell should show.

using System.Globalization;
using System.Text.RegularExpressions;
using unvell.ReoGrid;
using unvell.ReoGrid.DataFormat;

class WarekiNumericFirstYearFormatter : IDataFormatter
{
    static readonly CultureInfo wareki = new CultureInfo("ja-JP");

    static WarekiNumericFirstYearFormatter()
        => wareki.DateTimeFormat.Calendar = new JapaneseCalendar();

    public string FormatCell(Cell cell)
    {
        if (cell.Data is not DateTime d) return null;   // skip non-dates

        var s = d.ToString("ggy年M月d日", wareki);

        // 令和元年 → 令和1年 (also covers Meiji, Taisho, Showa, Heisei)
        return Regex.Replace(s, @"(?<=[治正和成])元年", "1年");
    }

    public bool PerformTestFormat() => true;
}

The lookbehind (?<=[治正和成]) matches 元年 only where it directly follows the last character of an era name (明, 大, 昭/令, 平), so the word 元年 anywhere else in a cell is left alone.

Apply it to the cells that need the other notation:

sheet.Cells["B8"].CustomDataFormatter = new WarekiNumericFirstYearFormatter();
// displays: 令和1年5月1日
The same sheet, where the last row now reads 令和1年5月1日 while the Heisei row still reads 平成元年1月8日
Result — the same sheet with the formatter on B8 only. B8 now reads 令和1年5月1日 while B6 keeps the default 平成元年1月8日, so you can see exactly which cell it touched.

Keep the DateTime format from SetRangeDataFormat in place. The custom formatter takes priority for display, but the string-to-DateTime conversion on edit is driven by the cell’s DateTime format — display and input parsing share the work.


What about printing and saving?

Printing uses the same rendering engine as the screen, so the wareki text in the cells goes to paper (or PDF) exactly as displayed. Wareki invoices and contracts print as-is — see Printing Spreadsheets in C# for the options.

Saving to .xlsx stores the cell values as real dates, not strings — the decisive difference from the string approach. Whoever receives the file can sort, filter, and calculate on those dates in Excel. If you also want Excel’s display to be wareki, set the cell format on the Excel side using Excel’s own convention (ggge"年"m"月"d"日") — as noted above, .NET and Excel spell their patterns differently. Since the data is alive as a date, the display format can be changed at any time, by anyone.


Bonus: the April-start fiscal year

Wareki’s constant companion in Japanese business apps is the fiscal year (年度), which runs April 1 to March 31. Use YEAR() naïvely and January–March transactions leak into the wrong year.

ReoGrid’s formula engine has IF / MONTH / YEAR built in, so the fiscal year can live in a cell formula:

// Fiscal year (Western) for the date in B3
sheet["D3"] = "=IF(MONTH(B3)>=4, YEAR(B3), YEAR(B3)-1)";

For a label like 令和8年度 (“fiscal Reiwa 8”), format the fiscal year’s starting date (April 1) in wareki with a one-line helper:

static string FiscalYearLabel(DateTime d)
{
    var start = d.Month >= 4 ? new DateTime(d.Year, 4, 1)
                             : new DateTime(d.Year - 1, 4, 1);
    return start.ToString("ggy", wareki) + "年度";   // e.g. 令和8年度
}

Same principle as everything above: the data stays a DateTime; only the presentation converts — so aggregation and comparison never break.


Wrapping up

Wareki support is less a feature problem than a design problem:

  • The moment a date becomes a string, sorting, formulas, filtering, and format changes all break
  • In ReoGrid, passing ggy年M月d日 + ja-JP to SetRangeDataFormat displays wareki while the data stays DateTime — the switch to JapaneseCalendar is automatic
  • Western-calendar input is converted to DateTime on edit, so “type Western, see wareki” just works
  • The formal 元年 (gannen) notation comes for free; IDataFormatter is there for when you need a different display
  • Printing matches the display; .xlsx saving keeps real dates — neither survives the string approach

Try ReoGrid in your own project

The Excel-compatible spreadsheet component for .NET WinForms and WPF. 30-day free trial — no credit card required.

Newsletter

New releases, straight to your inbox

Occasional updates on ReoGrid releases, features, and technical articles. Unsubscribe anytime.

Related articles

EDATE, EOMONTH, WORKDAY, NETWORKDAYS — Business Date Calculations with Spreadsheet Formulas in C#

"Due at the end of next month," "ship within 5 business days," "remind 3 business days before the deadline" — business apps are full of date rules that are surprisingly fiddly to hand-code with DateTime. Excel solved them long ago with EDATE, EOMONTH, WORKDAY, and NETWORKDAYS. This guide sorts out what each one does, the classic off-by-one traps, and how ReoGrid (supported in V4.5) runs the same formulas inside a WinForms / WPF app — no Office required.

When Search and Deduplication Quietly Fail on Japanese Data — Normalizing Full-Width / Half-Width Text in a C# App

An address in half-width kana, a phone number in full-width digits, the same company filed twice as "(株)" and "(株)" — Japanese input data mixes full-width and half-width characters, and as-is, search, deduplication, and totals all silently break. With ReoGrid you can bulk-convert using the Excel-compatible JIS / ASC functions, and auto-normalize on entry via AfterCellEdit. Build business data in C# that doesn't break on width inconsistency.

Stop Invoice Totals From Drifting by a Yen — Currency Formatting, Consumption Tax, and Rounding in C# with ReoGrid

Hold money in a double and you get rounding error; turn it into a string and totals and sorting break; round consumption tax in the wrong place and your invoice is off by a yen. Money breaks in business apps for predictable reasons. With ReoGrid, cell data stays numeric while it displays as ¥1,234,567 — and reduced-rate (8%/10%) subtotals and invoice-compliant rounding are just formulas.