Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Format "2024-02-29" to Buddhist Era so to obtain "2567-02-29" #2954

Open
mean-cj opened this issue Feb 29, 2024 · 4 comments
Open

Format "2024-02-29" to Buddhist Era so to obtain "2567-02-29" #2954

mean-cj opened this issue Feb 29, 2024 · 4 comments
Labels
enhancement macro candidate Rather than new methods, this could be a macro/mixin

Comments

@mean-cj
Copy link

mean-cj commented Feb 29, 2024

Hello,

Convert year "2024-02-29" to Buddhist Era, the result month is incorrect "2567-03-01"
https://play.phpsandbox.io/nesbot/carbon/wlJnA5ObQjKQBX89

Input AD (Anno Domini): 2024-02-29
Output BE (Buddhist Era): 2567-03-01

I encountered an issue with the following code:

use Carbon\Carbon;

// Assuming $gregorianYear is the Gregorian calendar year 
$gregorianYear = "2024-02-29";

// Convert to Buddhist calendar year
$buddhistYear = Carbon::createFromDate($gregorianYear)->addYears(543)->format("Y-m-d");

echo "AD (Anno Domini): $gregorianYear\n";
echo "BE (Buddhist Era): $buddhistYear\n";

Carbon version: 2.72.2 , 3.0.2
PHP version: 7.4.33, 8.2.15

I expected to get:
"2024-02-29" -> "2567-02-29"

Thanks!

@mean-cj mean-cj changed the title 2024-02-29 Convert year "2024-02-29" to Buddhist Era month result is incorrect "2567-03-01" Convert year "2024-02-29" to Buddhist Era, the result month is incorrect "2567-03-01" Feb 29, 2024
@kylekatarnls
Copy link
Collaborator

Hello,

I'm sorry for that but there is no way to support that.

First, there are legit cases where people doing Carbon::createFromDate($gregorianYear)->addYears($number) want to add $number years and expect to obtain a Gregorian date. And so it has to be a valid Gregorian date (either Feb 28th without overflow, or March 1st with overflow), but not February 29th because it does not exist in Gregorian year 2567.

Even if we would like to support that Carbon would not be able to as it's based on native PHP DateTime object which is always representing a single point in time with the constraint to be a valid Gregorian and valid in the given timezone.

You're recommended to split units not to handle Buddhist Era values using a Carbon or DateTime object:

use Carbon\Carbon;

$gregorianDate = '2024-02-29';
$carbonObject = Carbon::createFromDate($gregorianDate);

$buddhistDate = $carbonObject->addYears(543)->year . $carbonObject->format('-m-d');

echo "AD (Anno Domini): $gregorianDate\n";
echo "BE (Buddhist Era): $buddhistDate\n";

Thanks.

@mean-cj
Copy link
Author

mean-cj commented Feb 29, 2024

Hi @kylekatarnls

Thank you for your answer.

What do you think ?

Add my method "formatBuddhist()" for Buddhist Era year format
nesbot/carbon/src/Carbon/Traits/Converter.php

    public function formatBuddhist(string $format): string
    {

        if (strpos($format, 'o') !== false) {
            $format = str_replace('o', '[{1}]', $format);
        }
        
        if (strpos($format, 'Y') !== false) {
            $format = str_replace('Y', '[{2}]', $format);
        }
        
        if (strpos($format, 'y') !== false) {
            $format = str_replace('y', '[{3}]', $format);
        }

        $function = $this->localFormatFunction ?: static::$formatFunction;

        if (!$function) {
            $format = $this->rawFormat($format);
        }
        else if (\is_string($function) && method_exists($this, $function)) {
            $format = [$this, $function];
            $format = $function(...\func_get_args());
        }

        $timestamp = $this->getTimestamp();

        if (strpos($format, '[{1}]') !== false) {
            $format = str_replace('[{1}]', (date('o', $timestamp) + 543), $format);
        }
        
        if (strpos($format, '[{2}]') !== false) {
            $format = str_replace('[{2}]', (date('Y', $timestamp) + 543), $format);
        }
        
        if (strpos($format, '[{3}]') !== false) {
            $year = (date('y', $timestamp) + 43) % 100;
            $format = str_replace('[{3}]', $year, $format);
        }

        return $format;
    }
    $parse = Carbon::parse('2024-02-29 10.55.32');
    echo $parse->formatBuddhist("Y-m-d H:i:s"); // 2567-02-29 10:55:32
    echo $parse->formatBuddhist("d/m/y H:i:s"); // 29/02/67 10:55:32

If you agree, please add both version 2.x , 3.x versions.

@kylekatarnls kylekatarnls changed the title Convert year "2024-02-29" to Buddhist Era, the result month is incorrect "2567-03-01" Format "2024-02-29" to Buddhist Era so to obtain "2567-02-29" Feb 29, 2024
@kylekatarnls kylekatarnls added enhancement macro candidate Rather than new methods, this could be a macro/mixin labels Feb 29, 2024
@kylekatarnls
Copy link
Collaborator

kylekatarnls commented Feb 29, 2024

Hello,

I'm not sure yet if this should be included into Carbon itself, go into a separate package, or simply be documented as a macro.

I also see few little possible code changes, for instance, it's not useful to step by the timestamp and involve date() such as in date('o', $timestamp) you can simply do $this->format('o'). You can also use the method str_contains (even if you don't have PHP 8 yet as nesbot/carbon includes the symfony polyfill for it). And maybe all the if are not even worth it because if you call $format = str_replace('o', '[{1}]', $format); and that the string does not contain o it will just do nothing.

Be careful of $year = (date('y', $timestamp) + 43) % 100;, when it's < 10, you won't have a trailing zero. You'd get 29/02/7 while this format is supposed to give: 29/02/07, str_pad can be used to add the trailing 0.

Unfortunately, 2.x is now only receiving bugfixes. New features only comes into 3.x. On the other side, using macro, it would work on any object v2 or v3:

Carbon::macro('formatBuddhist', static function (string $format): string {
    $self = self::this();

    $format = strtr($format, [
        'o' => '[{1}]',
        'Y' => '[{2}]',
        'y' => '[{3}]',
    ]);

    $function = $self->localFormatFunction ?: static::$formatFunction;

    if (!$function) {
        $format = $self->rawFormat($format);
    } else if (\is_string($function) && method_exists($self, $function)) {
        $format = [$self, $function];
        $format = $function(...\func_get_args());
    }

    $buddhistYear = $self->year + 543;

    return strtr($format, [
        '[{1}]' => $self->format('o') + 543,
        '[{2}]' => $buddhistYear,
        '[{3}]' => str_pad($buddhistYear % 100, 2, '0', STR_PAD_LEFT),
    ]);
});

@kylekatarnls kylekatarnls reopened this Feb 29, 2024
@mean-cj
Copy link
Author

mean-cj commented Mar 1, 2024

Hello

Thank you so much for everything, suggestion and for your "Carbon" i love it.

The Buddhist calendar is a set of lunisolar calendars primarily used in Tibet, Cambodia, Laos, Myanmar, India, Sri Lanka, Thailand and Vietnam as well as in Malaysia and Singapore and by Chinese populations for religious or official occasions.

https://en.wikipedia.org/wiki/Buddhist_calendar

Actually, I think adding to carbon is also possible. Just a few lines more, or we can separate it into a separate package.

Have a good day, Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement macro candidate Rather than new methods, this could be a macro/mixin
Projects
None yet
Development

No branches or pull requests

2 participants