Search code examples
c++c++11c++-chrono

Loop over all months in chrono


I need iterate all months in a code:

for (auto m = std::chrono::January; m <= std::chrono::December; m++)
  std::cout << std::format(std::locale { "pt_BR.UTF-8" }, "{:L%B}\n", m);

But it happens it's a infinity loop, because the std::chrono::month increment has a modulo 12 + 1 behavior. So when the loop m variable reaches December (12), it wraps around to January (1).

I tried with std::views::iota:

for (auto m : std::views::iota(std::chrono::January) | std::views::take(12))
  std::cout << std::format(std::locale { "pt_BR.UTF-8" }, "{:L%B}\n", m);

But fails to compile as std::chrono::month don't satisfies the concept std::weakly_incrementable.


Solution

  • Your can use a unsigned loop!

    for (unsigned i = 1; i <= 12; i++)
      std::cout << std::format(std::locale { "pt_BR.UTF-8" }, "{:L%B}\n", 
                               std::chrono::month { i });
    

    If you get fancy you can define std::incrementable_traits for std::chrono::month to work with std::views::iota:

    namespace std {
      template <>
      struct incrementable_traits<std::chrono::month> 
        : incrementable_traits<unsigned> {};
    }
    
    for (auto m : std::views::iota(std::chrono::January) | std::views::take(12))
      std::cout << std::format(std::locale { "pt_BR.UTF-8" }, "{:L%B}\n", m);