# Library needed to deal with DataFrames
import pandas as pdConversion of Japanese Dates into the Gregorian Calendar
1 Introduction
In a recent blog post where I transliterated Japanese words written in hiragana or katakana into the Roman alphabet, I mentioned that the Japanese language has three sets of alphabets. Well now, I am here to tell you that the Japanese also have their own calendar.
Specifically, the Japanese has an era system which is different from the international standard. The months and days of the Japanese calendar are the same as the Gregorian calendar, but the naming convention for the year is different.
For example, 2026 is considered 令和 (Reiwa) 8th year with the Japanese calendar. Rewind 30 years to 1996: this was the 8th year of the 平成 (Heisei) era. Rewind another 30 years to 1966, and you arrive upon the 41st year of the 昭和 (Shouwa) era.
You quickly see that the number of years in each era is not fixed. Usually it is tied with the throne of the Japanese emperor and changes when the emperor changes. Most recently, the Heisei emperor stepped down, and was succeeded by his son in 2019, marking the start of the Reiwa era (Figure 1).
Additionally, some years on the Gregorian calendar are associated with two years in the Japanese calendar.
Take for example, the year 1989. This was both the last year of the 昭和 (Shouwa) era and the first year (also called 元年, read as “gan-nen”) of the 平成 (Heisei) era. Specifically, January 7th, 1989 was the last day of Shouwa, and January 8th, 1989 was the first day of Heisei.
Confused yet?
Don’t worry, even Japanese people forget what year it is in their own calendar.
In this tutorial, I will show you how to convert Japanese calendar dates into the Gregorian calendar with simple arithmetic. We’ll use real data, downloaded from the Japan Meteorological Agency (JMA) website, to show an example of the typical notation used with Japanese dates. Regular expressions will convert the string into a set of four variables (one era name and three values for year, month, day). Then, we’ll use a simple function to convert these values into its equivalent date in the Gregorian calendar.
1.1 What You’ll Learn in This Tutorial
By the end of this tutorial, you’ll learn how to:
- Use regular expressions to find and parse Japanese dates from the data string
- Deal with exceptions in the data entries
- First years of a Japanese era indicated with a kanji, instead of year
1 - Typos in the data
- First years of a Japanese era indicated with a kanji, instead of year
- Calculate the Gregorian equivalent of Japanese years by specifiying the starting year
If you prefer to skip the explanations and jump straight to the implementation, you can download the code from my GitHub repository.
Here is the list of things you’ll need to run the code.
1.2 Prerequisites
- A copy of either the
japanese-gregorian-calendar.ipynbJupyter notebook orjapanese-gregorian-calendar.pyPython script from my GitHub repository data/subfolder containing theame_master_20260324.csvfile- Python libraries
pandasre
1.3 Jargon
Gregorian calendar: The well-known calendar system used as the international standard in most of the world today.
Japanese calendar: An era-based system which resets when a new emperor reigns. Typically, the year is described as “era name” followed by “year number”. For example, 2026 is considered to be 令和 (Reiwa) 8th year. The month and day are the same as the Gregorian calendar.
Regular expression: Matching of text or string patterns against some template. By specifying the expected pattern of strings, parts of the text or substrings can be extracted.
2 Typical Example of How Japanese Dates are Recorded
Japanese dates require four things:
- the name of the era
- the year number
- the month
- the day
While there is a Japanese datetime object equivalent, reading Japanese dates as strings are usually the safest route, offering the greatest flexibility.
In one of my projects, where I made an interactive and informative map of all the weather stations in Japan, I worked with a CSV file containing information on the stations, downloaded from the Japan Meteorological Agency (JMA) website. One of the columns contained data on when data collection began at the weather station.
We’ll work with this dataset to demonstrate how we can convert Japanese dates from real data into the Gregorian calendar, as it gives us an idea of how Japanese dates are typically recorded. Let’s go ahead and read the data in the CSV file as a pandas DataFrame:
# Read the CSV file as a pandas DataFrame
fileName = './data/ame_master_20260324.csv'
amedas_df = pd.read_csv(fileName, encoding='CP932')Taking a look at the column noting the date that data collection began, we see that the data is indeed stored as a string.
# Only need the column containing the Japanese dates
japanese_dates = amedas_df['観測開始年月日']
japanese_dates.head(10)0 昭53.10.30
1 #昭50.4.1
2 平15.10.17
3 平15.1.1
4 昭53.10.30
5 平15.1.1
6 昭52.10.20
7 #昭52.10.24
8 (昭50.5.29)昭52.10.24
9 #昭52.10.19
Name: 観測開始年月日, dtype: str
The dates in this dataset are recorded in several formats. The document, ame_master.pdf (written in Japanese), explains that the data collection start date can take on one of four formats:
- The simplest and most intuitive format of
'(One kanji representing the era)(Year number).(Month).(Day)'. All weather data collection at the station began on this date.- Examples:
'昭53.10.30','平15.10.17','令4.11.16'for Shouwa, Heisei and Reiwa, respectively
- Examples:
- Just a
#(not seen in the first 10 entries above), which signifies that data collection began on November 1st, the 49th year of the Shouwa era. This is when the first weather stations began their operation. In other words,#is equivalent to'昭49.11.1'. - A
#, followed by a date in the format of 1. This signifies that precipitation data was first recorded on November 1st, the 49th year of the Shouwa era, but the weather station was later installed with devices to begin data collection on other meteorological parameters.- Example:
'#昭50.4.1'
- Example:
- A combination of two dates with the preceding date in parenthesis. The first date is when rainfall data collection began. All other data recorded at the site began on the second date
- Example:
'(昭50.5.29)昭52.10.24'
- Example:
3 Regex to Find and Parse the Japanese Dates
We’ll use two different regular expressions to search for # and the Japanese dates written in the format of '(One kanji representing the era)(Year number).(Month).(Day)'.
# Import regular expressions
import reThe regular expression amp_re = r'#' combined with re.findall() method searches for # in the date string. On the other hand, the regular expression date_re = r'([昭平令])(\d+)\.(\d+)\.(\d+)' searches for one of three kanji characters (corresponding to Shouwa, Heisei and Reiwa era), followed by one or more digits for the year number, the month and day (all having the regular expression of (\d+)), each separated by a .. Using () in the regex allows us to parse the era, year, month and day as we process them.
Applying these two regular expressions and printing out the outputs for the first couple data entries, we obtain the following:
# Regular expression to find `#` and `(One kanji representing the era)(Year number).(Month).(Day)`
amp_re = r'#'
date_re = r'([昭平令])(\d+)\.(\d+)\.(\d+)'
# Work through the first 10 lines in the DataFrame
for i in range(0, 10):
observation_date = japanese_dates[i]
# Search for `#`
amp_match = re.search(amp_re, observation_date)
if amp_match:
print('amp_match: ', amp_match[0], end='')
# Find all matches (there may be 0, 1 or 2) for the date format
date_match = re.findall(date_re, observation_date)
# Print out each date
for j in range(len(date_match)):
print('\tdate_match: ', date_match[j], end='\t')
# New line
print('') date_match: ('昭', '53', '10', '30')
amp_match: # date_match: ('昭', '50', '4', '1')
date_match: ('平', '15', '10', '17')
date_match: ('平', '15', '1', '1')
date_match: ('昭', '53', '10', '30')
date_match: ('平', '15', '1', '1')
date_match: ('昭', '52', '10', '20')
amp_match: # date_match: ('昭', '52', '10', '24')
date_match: ('昭', '50', '5', '29') date_match: ('昭', '52', '10', '24')
amp_match: # date_match: ('昭', '52', '10', '19')
Thus, we can successfully
- Find dates containing
# - Parse dates into a tuple of strings containing
('era name', 'year number', 'month', 'day')for data entries containing one or two dates
While these two regular expressions work beautifully for most of the data entries, I’m going to spill the beans and tell you that there are two cases where the regular expressions do not quite work. The code below shows the 7 (out of 1300) weather stations where neither regular expressions produced a match. In other words, no dates!
# Work through all the dates
for observation_date in japanese_dates:
# Search for `#`
amp_match = re.search(amp_re, observation_date)
# Find all matches (there may be 0, 1 or 2) for the date format
date_match = re.findall(date_re, observation_date)
# Print out the cases when no match for either were found
if (not amp_match) and (not date_match):
print(observation_date)平元.9.22
平元.12.1
平元.10.30
平元.12.20
令元.9.5
平.18.3.6
平.18.3.15
I’ll briefly explain why these cases arise, and their workarounds.
3.1 Gan-nen (元年) or the “Origin Year”
In the first five cases, we find the dates written as something like 平元.9.22. After the one kanji letter signifying the era, (平 in this case indicating the Heisei era), we are met with another kanji, 元, instead of finding a year number.
This is because the first year of an era is sometimes called 元年 (pronounced gan-nen), which roughly translates to root or origin year. It’s a special name given to just the first year.
To accommodate for this, we modify the date_re regular expression to expect one or more digits, or the 元 kanji when looking for the year number, using (元|\d+).
Let’s go through all the dates with the updated regular expression:
# New regular expression to account for "gan-nen"
date_re = r'([昭平令])(元|\d+)\.(\d+)\.(\d+)'
# Work through all the dates
for observation_date in japanese_dates:
# Search for `#`
amp_match = re.search(amp_re, observation_date)
# Find all matches (there may be 0, 1 or 2) for the date format
date_match = re.findall(date_re, observation_date)
# Print out the cases when no match for either were found
if (not amp_match) and (not date_match):
print(observation_date)平.18.3.6
平.18.3.15
We see we’ve successfully matched the dates containing 元. But we are still left with two data entries that have no matches.
3.2 Typos and Errors During Data Input
Humans make mistakes. And since humans are still a major part of the data entry pipeline, sometimes, data can have typos.
The two remaining dates of 平.18.3.6 and 平.18.3.15 are such the case. The correct format should have been 平18.3.6 and 平18.3.15, without the . after the 平. Luckily, regular expressions can handle such “optional” characters with a ?. In the case of a . which may or may not be present, we signify it with a \.?.
Let’s run through all data entries using the updated regular expression:
# New regular expression to account for "gan-nen" and the '.' that may or may not be present
date_re = r'([昭平令])\.?(元|\d+)\.(\d+)\.(\d+)'
# Work through all the dates
for observation_date in japanese_dates:
# Search for `#`
amp_match = re.search(amp_re, observation_date)
# Find all matches (there may be 0, 1 or 2) for the date format
date_match = re.findall(date_re, observation_date)
# Print out the cases when no match for either were found
if (not amp_match) and (not date_match):
print(observation_date)We’ve found that all data entries find a match when looking for Japanese dates.
We are now ready to convert the matched outputs from the regex operations into Gregorian dates.
4 Convert Japanese Dates into the Gregorian Calendar
The month and the day are the same in the Japanese and Gregorian calendars. So, the only conversion we need is the year. This can be done with simple addition.
Let’s think of the Heisei era, which started in 1989. Subsequently, 1990 was Heisei 2nd year and 1991 was Heisei 3rd year. This means that if we identify “year 0” for the Heisei era, we can convert the Japanese years into Gregorian years by simple addition of the Japanese year number to “year 0” of the era.
In the case of the Heisei era, since 1989 is year 1, 1988 would be year 0. Add 3 years and you get 1988 + 3 = 1991. Indeed, 1991 is Heisei 3rd year. Add 8 years and you get 1988 + 8 = 1996. Remember how I said how 2026 is Reiwa year 8 and 30 years ago (ie. 1996) was Heisei year 8 near the start of the blog post? There you go. Simple addition.
Similarly, Shouwa era started in 1926, making 1925 “year 0”. Reiwa era begun in 2019, so “year 0” would be 2018.
Below is a function I wrote which can convert the tuple of strings, containing information about the Japanese dates, into its equivalent Gregorian date. The output is written as a string in the format of yyyy-mm-dd. It deals with only the three most recent eras (Shouwa, Heisei and Reiwa), but you can add to the if-else statements to manage more eras.
def ConvertJapaneseDates2Gregorian(str_match):
"""Convert a date in the Japanese calendar to the Gregorian calendar.
AUTHOR: Mai Tanaka (www.DataDrivenMai.com)
DATE: 2026-08-13
REQUIRES: str_match = tuple of the Japanese date in the form (era, year, month, day)
PROMISES: return_str = string of the date in the Gregorian calendar in the form 'YYYY-MM-DD'
"""
# Convert year number, month and day from strings into integers
# Indices 0 and 1 are associated with the year
era = str_match[0]
year = str_match[1]
# If we have '元', convert it to 1
if year == '元':
year = 1
else:
year = int(year)
# Indices 2 and 3 are associated with the month and day
month = int(str_match[2])
day = int(str_match[3])
# Convert era names into Gregorian years
if '昭' in era:
gregorian_year = year + 1925
elif '平' in era:
gregorian_year = year + 1988
elif '令' in era:
gregorian_year = year + 2018
else:
raise ValueError("Unknown era: {}".format(era))
# Format the output as yyyy-mm-dd
return_str = "{}-{:02d}-{:02d}".format(gregorian_year, month, day)
return return_strLet’s put everything together, and convert the starting Japanese dates of data collection into the Gregorian dates of when rainfall was first recorded, and when all other weather data were recorded at the station. We’ll store both the original dates and the converted outputs into the df_dates DataFrame:
# Two regular expressions
amp_re = r'#'
date_re = r'([昭平令])\.?(元|\d+)\.(\d+)\.(\d+)'
# Empty dataframe
df_dates = pd.DataFrame()
# Work through all data entries
for i in range(0, len(japanese_dates)):
# The observation start date
observation_date = japanese_dates[i]
# Find matches to the two regular expressions
amp_match = re.search(amp_re, observation_date)
date_match = re.findall(date_re, observation_date)
# Temporary storage of the dates
dates = []
# For `#`, add the date Nov 1, 1974
if amp_match:
dates.append('1974-11-01')
# For any other date match, convert Japanese dates to Gregorian dates
if date_match:
for j in range(len(date_match)):
# Convert the date to the Gregorian calendar
new_date = ConvertJapaneseDates2Gregorian(date_match[j])
dates.append(new_date)
# Once dates are found, insert them into dataframe
# Insert the original date
df_dates.loc[i, 'original observation_date'] = observation_date
# Insert the first date we found as rainfall data collection start date
df_dates.loc[i, 'observation_start_date_rain'] = dates[0]
# For all other weather data, the start date for records depends on whether we have a second date or not
if len(dates) == 2:
other_date = dates[1]
else:
other_date = dates[0]
df_dates.loc[i, 'observation_start_date_other'] = other_dateThe Japanese dates have been converted into the Gregorian calendar, and the results are neatly organized in a pandas DataFrame.
df_dates.head()| original observation_date | observation_start_date_rain | observation_start_date_other | |
|---|---|---|---|
| 0 | 昭53.10.30 | 1978-10-30 | 1978-10-30 |
| 1 | #昭50.4.1 | 1974-11-01 | 1975-04-01 |
| 2 | 平15.10.17 | 2003-10-17 | 2003-10-17 |
| 3 | 平15.1.1 | 2003-01-01 | 2003-01-01 |
| 4 | 昭53.10.30 | 1978-10-30 | 1978-10-30 |
We may choose to save the data as a CSV file in case we’d like to use it later.
# Specify a strong filename in a directory that exists
fileName = 'japanese_gregorian_calendar_jupyter.csv'
dirName = 'data/'
savefileName = dirName + fileName
# Save the output as a CSV file
df_dates.to_csv(savefileName, index=False, encoding='utf-8')5 Summary
There you have it!
In this short tutorial, we have done the following:
- Applied regular expressions to find and parse the era name, year number, month and day from a real data containing Japanese dates
- Improved the regular expressions to work with
元or gan-nen, and human data entry errors - Converted Japanese years into Gregorian years by simple addition of the Japanese years to “year 0” for the era in question
While the code here is written to work with the three most recent Japanese eras of Shouwa, Heisei and Reiwa, you can easily add on more Japanese eras as if-else statements in the ConvertJapaneseDates2Gregorian() function.
Hopefully, you don’t feel as intimidated as before looking at data containing Japanese dates.
6 Further Readings
- Look up the three unique identifiers for each JMA weather station quickly on my interactive and informative map of all AMeDAS weather stations in Japan
- Read this blog post to transcribe or transliterate Japanese words into the Roman alphabet

