Best Practices for Handling Shamsi Calendar Conversions and Localized Date Logic in Elixir Apps?

I’m working on an Elixir/Phoenix application that needs to support multiple calendar systems — specifically converting between Gregorian dates and alternative civil calendars (for example, Jalali/Shamsi).

Before I reinvent the wheel, I’d really appreciate hearing from people who’ve tackled similar problems:

  • Do you rely entirely on Elixir’s built-in Calendar behaviour and implement custom modules?

  • Or do you prefer using libraries like ex_cldr_calendars for production-grade localization?

  • How would you structure a system where users can switch calendars but you still need a reliable, consistent underlying format (e.g., always store in UTC/Gregorian, but display in regional calendars)?

  • Any pitfalls or “wish I knew this earlier” moments when dealing with alternative calendar math, date pickers, or timezone edge cases?

I’m mainly looking for architectural guidance or lessons learned from those who’ve deployed multilingual, multi-calendar Elixir applications in the real world.

Thanks in advance, I’d love to hear how others have approached this.

1 Like

Hi @sarah.navin hope you are well. Please see this lib GitHub - jalaali/elixir-jalaali: Jalaali (also known as Jalali, Persian, Khorshidi, Shamsi) calendar implementation in Elixir.

Maybe some your problems fixed!

But overall, I personally prefer that dates be stored in the database in Gregorian format and then converted to Shamsi or other formats only when displayed.

4 Likes

converting between Gregorian dates and alternative civil calendars (for example, Jalali/Shamsi )

ex_cldr_calendars_persian implements this Charms calendar which should, I hope, provide a ready-made solution for you. ex_cldr_dates_times provides localised date/time formatting for any calendar.

Do you rely entirely on Elixir’s built-in Calendar behaviour and implement custom modules?

All of the ex_cldr_calendars comply with the Calendar behaviour but also add the Cldr.Calendar behaviour to support localization.

Or do you prefer using libraries like ex_cldr_calendars for production-grade localization?

ex_cldr_calendars is intended to provide out-of-the-box support for localised calendars. If there are gaps in requirements let me know.

3 Likes

Dear shahryarjb

Thanks for the pointer to the elixir-jalaali library. It looks like a clean, focused implementation of the core date conversion algorithms, which is a great starting point.

You’ve hit on the critical architectural principle: store in Gregorian (UTC), display in the user’s calendar. That’s the cornerstone of any maintainable system.

Your suggestion actually reminds me of a fascinating case study I came across while researching this: the WordPress Jalali (Persian) Date plugin. At first glance, WordPress (PHP) and Elixir have little in common, but the architectural patterns and user-facing problems that plugin solves are directly transferable and highly instructive for an Elixir/Phoenix app:

  1. The “Leaky Abstraction” Problem: The WordPress plugin doesn’t just convert dates; it has to hook into every layer where a date appears—posts, comments, admin panels, feeds. This mirrors our challenge in Phoenix. We need to think beyond a conversion function and consider: Ecto schemas, LiveView date bindings, form inputs (datetime_select), and even cron-like background jobs. The elixir-jalaali lib gives us the core math, but we need to build the integration “plumbing” around it, much like that WordPress plugin had to do for WP’s hooks and filters.

  2. UI Component Integration: One of the plugin’s biggest features is providing a Shamsi date picker for the admin UI. This is a non-trivial front-end challenge we’ll also face. Studying how they wrapped or replaced the standard Gregorian date picker provides a blueprint for how we might integrate a similar component into our LiveView or JavaScript frontend. The logic for validating and converting the picked date back to Gregorian for storage is a key piece of logic we’d have to write ourselves.

  3. Handling Inevitable Edge Cases: Over a decade of use, that plugin has dealt with real-world edge cases: how to handle pre-plugin Gregorian content, how to manage RSS feeds that expect Gregorian dates, and how to properly localize not just dates but also associated terms (“AM/PM” vs. “ق.ظ / ب.ظ”). These are the exact “pitfalls” and “wish I knew” moments I was asking about. The solutions they codified are valuable design inputs.

So, while we aren’t using PHP code, the WordPress Jalali plugin serves as a mature, real-world specification for the full suite of features a multi-calendar Elixir app needs. We can use elixir-jalaali (or ex_cldr_calendars_persian as @kip suggested) as our core conversion engine, but we should look to the holistic integration approach of that WordPress plugin as our guide for the architecture.

I would check elixir-jalali ASAP and put reasonable feedback for any future reference.

Thanks again for the library link, it’s a solid piece of the puzzle.

1 Like

Dear kip

Thank you for the detailed and authoritative response! It’s incredibly valuable to get guidance directly from the ex_cldr core team, especially when dealing with something as nuanced as calendar systems and localization.

The combination you’ve described—ex_cldr_calendars_persian for the calendar implementation and ex_cldr_dates_times for localized formatting—sounds like the most comprehensive, production-ready solution available in the Elixir ecosystem. I particularly appreciate that these libraries:

  1. Implement both standard behaviors: Compliance with Elixir’s built-in Calendar behavior ensures interoperability with the broader ecosystem (like Date/Time functions, Ecto, etc.), while the Cldr.Calendar behavior provides the localization framework needed for proper internationalization.

  2. Provide end-to-end functionality: Having conversion, validation, and localization handled within a coherent, well-tested suite dramatically reduces the integration surface area compared to piecing together multiple libraries.

  3. Come with community and maintenance backing: Knowing these are actively maintained as part of the ex_cldr project gives significant confidence for production use.

This approach seems to answer all the key concerns in my original post: reliable underlying storage (Gregorian/UTC), proper display formatting in regional calendars, and production-grade localization support. The fact that these libraries handle both the calendar math and the user-facing presentation aspects, rather than just one or the other, makes them particularly compelling

I’ll definitely be moving forward with implementing ex_cldr_calendars and will certainly reach out if I encounter any gaps or edge cases in our specific use case.

Thank you again for building and maintaining these essential tools for the Elixir community!

Sarah