সূর্য সিদ্ধান্ত পঞ্জিকা সকল প্রবন্ধ

বার ও পঞ্জিকা দিবস: civil midnight নয়, সূর্যোদয় থেকে দিনের পরিচয় কীভাবে নির্ধারিত হয়?

Civil day, sunrise-to-sunrise Panchanga day ও Julian Day-এর পার্থক্য; pre-sunrise rule, DST-safe next sunrise, historical weekday এবং C# implementation।

“আজ বৃহস্পতিবার”—এই বাক্যটি সাধারণ ঘড়ি ও পঞ্জিকা দুই ক্ষেত্রেই বলা যায়, কিন্তু day boundary একই নয়। Civil calendar-এ দিন রাত ১২টায় বদলায়; প্রথাগত Panchanga day স্থানীয় সূর্যোদয়ে শুরু হয়ে পরের স্থানীয় সূর্যোদয়ে শেষ হয়। একটি production app-এ এই দুই পরিচয় পাশাপাশি রাখতে হবে—একটিকে আরেকটির বদলে ব্যবহার করলে বিশেষ করে মধ্যরাত থেকে সূর্যোদয়ের আগের output ভুল হবে।

একই গণনায় চার রকম day boundary

ধারণাBoundaryকাজ
Civil dayস্থানীয় midnight থেকে পরের midnightGregorian/Julian date, অফিসিয়াল timestamp, URL input
Panchanga/Vedic dayস্থানীয় sunrise থেকে পরের sunriseবার, sunrise-state, দৈনিক তিথি–নক্ষত্র–যোগ–করণ ও উৎসব
Julian DayAstronomical continuous count; পূর্ণসংখ্যা boundary noon-এEphemeris, root solving, historical continuity
Event intervalদুটি exact astronomical instantতিথি/নক্ষত্র/করণ/যোগের শুরু–শেষ

এগুলোকে একটি DateTime field-এ গুঁজে দিলে অর্থ হারায়। Internal calculation-এ absolute instant বা Julian Day, display-এ local civil date, আর daily report-এ sunrise-anchored span আলাদা object হিসেবে রাখা নিরাপদ।

বার বা Vāra কী?

বার—সংস্কৃতে Vāra—পঞ্চাঙ্গের পাঁচ অঙ্গের একটি। এই পরিচয় সূর্যোদয়-anchored day span-এর সঙ্গে যুক্ত। যে স্থানীয় civil date-এর সূর্যোদয় span-টি শুরু করেছে, সেই date-এর weekday-ই span-এর বার।

Half-open interval [start, end) ব্যবহার জরুরি: ঠিক প্রথম sunrise instant বর্তমান day-এর অন্তর্ভুক্ত; ঠিক পরের sunrise instant পরবর্তী day-এর অন্তর্ভুক্ত। এতে shared boundary দুই দিনে duplicate হয় না।

সাত বারের stable mapping

.NET DayOfWeekKeyবাংলাসংস্কৃত নাম
Sunday = 0ravivaraরবিবাররবি/আদিত্যবার
Monday = 1somavaraসোমবারসোমবার
Tuesday = 2mangalavaraমঙ্গলবারমঙ্গলবার
Wednesday = 3budhavaraবুধবারবুধবার
Thursday = 4guruvaraবৃহস্পতিবারগুরু/বৃহস্পতিবার
Friday = 5shukravaraশুক্রবারশুক্রবার
Saturday = 6shanivaraশনিবারশনিবার

Database ও API-তে বাংলা display text-এর বদলে stable key রাখুন। ভবিষ্যতে Assamese বা English language file যোগ হলেও calculation key বদলাবে না।

সূর্যোদয় থেকে পরের সূর্যোদয়

ধরা যাক কোনো শহরে বৃহস্পতিবার sunrise 05:45 এবং শুক্রবার sunrise 05:46। তাহলে:

বৃহস্পতিবার রাত ১১টা এবং শুক্রবার ভোর ৩টা—দুটিই একই sunrise-to-sunrise Panchanga day-তে পড়ে। Civil date আলাদা হলেও বার বদলায়নি। শুক্রবারের local sunrise-এ বার শুক্রবার হবে।

Pre-sunrise instant কেন আগের পঞ্জিকা দিবস?

Live calculation-এর জন্য local timestamp-কে আজকের sunrise-এর সঙ্গে তুলনা করতে হবে:

  • instant ≥ আজকের sunrise: anchor date আজ;
  • instant < আজকের sunrise: anchor date গতকাল;
  • instant = আগামী sunrise: পরের Panchanga day শুরু।

এখানে “গতকাল” মানে local civil date minus one। এরপর সেই anchor date-এর sunrise এবং তার পরের civil date-এর sunrise স্বাধীনভাবে গণনা করতে হবে।

Date report mode ও live mode এক নয়

ModeInputAnchorউদাহরণ
Date reportCity + civil date Dসরাসরি D৮ অক্টোবরের দৈনিক পঞ্জিকা = ৮ অক্টোবর sunrise → ৯ অক্টোবর sunrise
Live nowCity + exact instantআজ বা আগের date, sunrise comparison-এর পরে৯ অক্টোবর 03:00; sunrise 05:50 হলে anchor ৮ অক্টোবর

Date report-এ user একটি civil date-এর page চান; সেখানে span সবসময় সেই date-এর sunrise থেকে শুরু। Live mode-এ user এখনকার Panchanga state চান; তাই sunrise comparison বাধ্যতামূলক। একই method-এ দুই অর্থ মেশালে cache key, URL ও header অস্পষ্ট হয়।

একই UTC instant, কিন্তু ভিন্ন Panchanga day

সূর্যোদয় স্থানীয়। একই UTC instant কলকাতা, ঢাকা ও নিউ ইয়র্কে:

  • ভিন্ন local civil date বা clock time হতে পারে;
  • কোনো শহরে sunrise পেরিয়ে গেছে, অন্য শহরে এখনও হয়নি;
  • তাই bar ও Panchanga day anchor-ও আলাদা হতে পারে।

প্রতিটি request-এ latitude, longitude এবং time-zone identifier একসঙ্গে রাখতে হবে। শুধু offset যেমন +05:30 ভবিষ্যৎ/অতীত DST rule প্রকাশ করে না; শুধু city name-ও নির্ভরযোগ্য coordinate নয়।

“সূর্যোদয়” কোন definition?

সূর্যোদয়ের একাধিক computational convention আছে। উদাহরণ:

Profileধারণাফল
Upper limb + refractionসূর্যের upper edge দৃশ্যমান; standard refraction ও semidiameter ধরাসাধারণ almanac sunrise-এর কাছাকাছি
Sun center + standard refractionCenter-এর apparent crossingUpper-limb profile থেকে সময় আলাদা
Center + no refractionGeometric center horizon crossingResearch/engine-specific output

Rashtriya Panchang-এর official explanation upper limb এবং refraction-ভিত্তিক convention বর্ণনা করে; U.S. Naval Observatory-এর standard computational sunrise-এ Sun center-এর zenith distance 90.8333° ব্যবহৃত হয়—যা semidiameter ও typical refraction অন্তর্ভুক্ত করে। আপনার app যদি Swiss Ephemeris-এর center/no-refraction profile ব্যবহার করে, সেটি ভুল বলে গোপনে বদলাবেন না; বরং profile name স্পষ্ট দেখান এবং তুলনার সময় একই definition ব্যবহার করুন।

sunriseProfile = "sun-center-no-refraction"
// অথবা
sunriseProfile = "upper-limb-standard-refraction"

DST-তে next sunrise কখনোই শুধু +24 hours নয়

New York-এর মতো অঞ্চলে daylight-saving transition-এর রাতে local clock এক ঘণ্টা এগিয়ে বা পিছিয়ে যায়। ফলে:

// ভুল
nextSunrise = sunrise.AddHours(24);

// সঠিক ধারণা
sunrise     = CalculateSunrise(localDate, location);
nextSunrise = CalculateSunrise(localDate.AddDays(1), location);

প্রতিটি sunrise-কে নিজ civil date, coordinate ও time-zone rule দিয়ে independently গণনা করুন। Absolute UTC interval DST transition-এর কাছে ২৩ বা ২৫ ঘণ্টার আশেপাশে হতে পারে; তার সঙ্গে seasonal sunrise shift-ও যোগ হয়। এটি error নয়।

DateTimeOffset absolute instant-এর জন্য উপযোগী, কিন্তু একা future/historical zone rule ধারণ করে না। Zone conversion-এর জন্য TimeZoneInfo বা আপনার versioned time-zone provider রাখুন।

তিথি–নক্ষত্র–করণ–যোগ কোন দিনে যাবে?

Day span তৈরি হলে event assignment সহজ:

এই span-এর মধ্যে শেষ হওয়া সব তিথি, নক্ষত্র, করণ ও যোগ chronological order-এ দেখান। Midnight-এর পরে কিন্তু next sunrise-এর আগে event হলে “নিশা” বা extended-hour notation ব্যবহার করা যায়; day পরিবর্তন করবেন না। Official Rashtriya Panchang-এ midnight-এর পরের event time ২৫, ২৬ ইত্যাদি ঘণ্টায় প্রকাশের convention-ও ব্যাখ্যা করা আছে।

কোনো element পরের sunrise-এর আগে শেষ না হলে আপনার format অনুযায়ী অহোরাত্র বা “পরবর্তী সূর্যোদয়ের পর” দেখানো যেতে পারে। Exact next-sunrise boundary পরের day-এর event—বর্তমান day-এ duplicate নয়।

Julian/Gregorian date বদলালেও weekday sequence ভাঙে না

একই astronomical instant-কে proleptic Gregorian ও Julian calendar-এ দুই আলাদা date label দেওয়া যায়। ১৫৮২ সালের reform-এ কিছু civil date label বাদ পড়েছিল; কিন্তু absolute day ও weekday sequence থেকে কোনো দিন হারায়নি। তাই historical output-এ:

  • core chronology Julian Day/Julian Day Number-এ রাখুন;
  • Julian ও Gregorian label presentation layer-এ তৈরি করুন;
  • একই sunrise instant-এর দুই label-এর weekday অবশ্যই একই হবে;
  • calendar system বদলে weekday পুনর্গণনায় artificial jump তৈরি করবেন না।

৫৯৪ খ্রিস্টাব্দের মতো early historical year-এ .NET DateTime দিয়ে সব intermediate civil conversion করা ঝুঁকিপূর্ণ। Astronomy ও weekday core-এ JD/JDN, আর display-এর জন্য tested Julian/Gregorian converter ব্যবহার করুন। Historical time zone-ও আধুনিক national offset ধরে নেওয়া উচিত নয়; প্রয়োজনে fixed LMT/research profile প্রকাশ করুন।

সূর্যোদয় না হলে কী হবে?

উচ্চ অক্ষাংশে কোনো civil date-এ sunrise নাও ঘটতে পারে। Production code-এর ভুল fallback হলো silently midnight-কে sunrise ধরা। সঠিক আচরণ:

  • NoSunrise বা UnsupportedLatitude status ফেরত দিন;
  • UI-তে location/date-সহ পরিষ্কার ব্যাখ্যা দিন;
  • কোনো ধর্মীয় polar-day convention নিলে authority ও algorithm প্রকাশ করুন;
  • normal-latitude cache-এর সঙ্গে fallback result মেশাবেন না।

C# 5-compatible data model

public enum VaraKind
{
    Ravivara = 0,
    Somavara = 1,
    Mangalavara = 2,
    Budhavara = 3,
    Guruvara = 4,
    Shukravara = 5,
    Shanivara = 6
}

public sealed class PanchangaDaySpan
{
    public DateTime LocalAnchorDate { get; set; }
    public DateTimeOffset SunriseUtc { get; set; }
    public DateTimeOffset NextSunriseUtc { get; set; }
    public DateTimeOffset LocalSunrise { get; set; }
    public DateTimeOffset LocalNextSunrise { get; set; }
    public VaraKind Vara { get; set; }
    public string TimeZoneId { get; set; }
    public string SunriseProfile { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }
}

public interface ISunriseCalculator
{
    DateTimeOffset CalculateSunriseUtc(
        DateTime localCivilDate,
        DesktopLocation location);
}

LocalAnchorDate-এর Kind Unspecified রাখা ভালো—এটি একটি calendar label, machine-local instant নয়। Sunrise calculator absolute UTC instant ফেরত দেবে।

Civil date থেকে day span তৈরি

public sealed class PanchangaDayResolver
{
    readonly ISunriseCalculator sunriseCalculator;

    public PanchangaDayResolver(ISunriseCalculator sunriseCalculator)
    {
        if (sunriseCalculator == null)
            throw new ArgumentNullException("sunriseCalculator");

        this.sunriseCalculator = sunriseCalculator;
    }

    public PanchangaDaySpan BuildForCivilDate(
        DateTime localDate,
        DesktopLocation location)
    {
        DateTime anchor = DateTime.SpecifyKind(
            localDate.Date,
            DateTimeKind.Unspecified);

        DateTimeOffset sunriseUtc =
            sunriseCalculator.CalculateSunriseUtc(anchor, location)
                .ToUniversalTime();

        DateTimeOffset nextSunriseUtc =
            sunriseCalculator.CalculateSunriseUtc(
                anchor.AddDays(1), location).ToUniversalTime();

        if (nextSunriseUtc <= sunriseUtc)
            throw new InvalidOperationException(
                "Next sunrise must be after sunrise.");

        TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById(
            location.TimeZoneId);

        return new PanchangaDaySpan
        {
            LocalAnchorDate = anchor,
            SunriseUtc = sunriseUtc,
            NextSunriseUtc = nextSunriseUtc,
            LocalSunrise = TimeZoneInfo.ConvertTime(sunriseUtc, zone),
            LocalNextSunrise = TimeZoneInfo.ConvertTime(nextSunriseUtc, zone),
            Vara = (VaraKind)(int)anchor.DayOfWeek,
            TimeZoneId = location.TimeZoneId,
            SunriseProfile = location.SunriseProfile,
            Latitude = location.Latitude,
            Longitude = location.Longitude
        };
    }
}

.NET-এর DayOfWeek Sunday=0 থেকে Saturday=6; উপরের VaraKind একই order-এ হওয়ায় cast নিরাপদ। যদি enum order বদলান, explicit switch ব্যবহার করুন।

Exact instant থেকে live Panchanga day

public PanchangaDaySpan ResolveForInstant(
    DateTimeOffset instantUtc,
    DesktopLocation location)
{
    TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById(
        location.TimeZoneId);

    DateTimeOffset utc = instantUtc.ToUniversalTime();
    DateTimeOffset local = TimeZoneInfo.ConvertTime(utc, zone);
    DateTime localDate = DateTime.SpecifyKind(
        local.Date,
        DateTimeKind.Unspecified);

    DateTimeOffset todaySunriseUtc =
        sunriseCalculator.CalculateSunriseUtc(
            localDate, location).ToUniversalTime();

    DateTime anchorDate = utc < todaySunriseUtc
        ? localDate.AddDays(-1)
        : localDate;

    return BuildForCivilDate(anchorDate, location);
}

Comparison সবসময় absolute UTC instant-এ করা হয়েছে। Local wall time compare করলে ambiguous DST hour এবং offset mismatch-এর ঝুঁকি বাড়ে।

বারের localized display

static string VaraNameBn(VaraKind value)
{
    switch (value)
    {
        case VaraKind.Ravivara: return "রবিবার";
        case VaraKind.Somavara: return "সোমবার";
        case VaraKind.Mangalavara: return "মঙ্গলবার";
        case VaraKind.Budhavara: return "বুধবার";
        case VaraKind.Guruvara: return "বৃহস্পতিবার";
        case VaraKind.Shukravara: return "শুক্রবার";
        case VaraKind.Shanivara: return "শনিবার";
        default: throw new ArgumentOutOfRangeException("value");
    }
}

JD/JDN থেকে historical weekday

Modern DateTime range বা calendar behavior-এর উপর নির্ভর না করে JDN থেকে weekday:

static int Mod(int value, int modulus)
{
    int result = value % modulus;
    return result < 0 ? result + modulus : result;
}

static VaraKind VaraFromLocalJulianDay(
    double julianDayUt,
    double utcOffsetSeconds)
{
    double localJd = julianDayUt + utcOffsetSeconds / 86400.0;
    long localJdn = (long)Math.Floor(localJd + 0.5);
    int sundayZero = Mod((int)((localJdn + 1L) % 7L), 7);
    return (VaraKind)sundayZero;
}

এই helper local civil weekday label দেয়; Panchanga bar-এর জন্য sunrise anchor instant/date ব্যবহার করুন। Historical offset অবশ্যই chosen research profile থেকে আসবে। Modern TimeZoneInfo data বহু শতাব্দী আগে নির্ভুল local mean time দেয়—এমন অনুমান করবেন না।

API ও XML output

{
  "requestedCivilDate": "2026-10-09",
  "panchangaAnchorDate": "2026-10-08",
  "vara": {
    "key": "guruvara",
    "nameBn": "বৃহস্পতিবার"
  },
  "sunrise": "2026-10-08T05:54:21+06:00",
  "nextSunrise": "2026-10-09T05:54:43+06:00",
  "timeZoneId": "Bangladesh Standard Time",
  "latitude": 23.8103,
  "longitude": 90.4125,
  "sunriseProfile": "sun-center-no-refraction",
  "assignmentRule": "sunrise-inclusive-next-sunrise-exclusive"
}

উপরেরটি live pre-sunrise request-এর format example; সময়গুলো test vector নয়। Date-only endpoint হলে requestedCivilDate ও panchangaAnchorDate একই হবে।

<panchanga-day anchor-date="2026-10-08"
               vara-key="guruvara"
               vara-bn="বৃহস্পতিবার"
               timezone="Bangladesh Standard Time"
               sunrise-profile="sun-center-no-refraction">
  <sunrise local="2026-10-08T05:54:21+06:00" />
  <next-sunrise local="2026-10-09T05:54:43+06:00" />
  <assignment>[sunrise, next-sunrise)</assignment>
</panchanga-day>

Cache key-তে অন্তত anchor date, rounded/exact coordinates, time-zone ID, sunrise profile এবং astronomy version রাখুন। শুধু civil date + city label যথেষ্ট নয়।

সাধারণ implementation error

ভুলকী সমস্যা হয়সংশোধন
Midnight-এ Panchanga day বদলানোPre-sunrise bar ও festival ভুলLocal sunrise comparison
Now.DayOfWeek সরাসরি ব্যবহারভোরের live report এক দিন এগিয়েAnchor date resolve করে weekday
Next sunrise = sunrise + 24hDST ও seasonal shift ভুলপরের civil date independently calculate
Local wall-time compareDST ambiguous timeUTC instant compare
Offset-ই time zoneHistorical/future DST হারায়Zone ID + versioned rules
Location ও zone mismatchSunrise local time ভুলValidated location profile
Sunrise profile গোপনPrinted Panchanga mismatch ব্যাখ্যাতীতDefinition/version publish
Exact next sunrise current day-এBoundary duplicateHalf-open interval
Julian/Gregorian gap-এ weekday resetHistorical sequence ভাঙেContinuous JD/JDN core
No sunrise হলে midnight fallbackঅপ্রকাশিত invented resultExplicit status/policy

Validation checklist

  1. Exact sunrise instant নতুন Panchanga day;
  2. Sunrise-এর এক second আগে আগের day;
  3. Sunrise-এর এক second পরে নতুন day;
  4. Exact next sunrise current span থেকে excluded;
  5. Local midnight-এ bar অপরিবর্তিত, যদি sunrise না হয়;
  6. Pre-sunrise local time আগের anchor date;
  7. Post-sunrise local time বর্তমান anchor date;
  8. Date report-এ requested date-ই anchor;
  9. Live mode-এ sunrise comparison;
  10. Sunday=0 enum mapping;
  11. সাতটি stable key language-independent;
  12. Kolkata fixed-zone normal day;
  13. Dhaka fixed-zone normal day;
  14. New York DST spring-forward;
  15. New York DST fall-back;
  16. Next sunrise independently calculated;
  17. Span duration ২৪ ঘণ্টা hard-code নয়;
  18. Same UTC instant, Dhaka বনাম New York;
  19. Latitude/longitude-zone mismatch rejected;
  20. Invalid zone ID handled;
  21. Sunrise calculator no-result handled;
  22. Upper-limb/refraction profile;
  23. Center/no-refraction profile;
  24. Profile change cache invalidates;
  25. Event at sunrise included;
  26. Event inside span included;
  27. Event at next sunrise excluded;
  28. Post-midnight event একই Panchanga day;
  29. Multiple Karana transitions chronological;
  30. No duplicate shared-boundary event;
  31. “অহোরাত্র” path;
  32. Julian/Gregorian dual label একই JD;
  33. Dual label-এ একই weekday;
  34. ১৫৮২ reform continuity;
  35. ১৭৫২ regional reform label test;
  36. ৫৯৪ খ্রিস্টাব্দ JD/JDN weekday;
  37. Historical fixed-offset profile;
  38. Negative/proleptic date modulo test;
  39. UTC comparison around offset change;
  40. API ও HTML একই anchor date;
  41. XML ও printed report একই bar;
  42. URL date semantics documented;
  43. Cache key-তে coordinate/zone/profile;
  44. Polar no-sunrise explicit error;
  45. Regression against trusted printed Panchanga।

উপসংহার

Civil date রাত ১২টায় বদলায়, কিন্তু Panchanga day স্থানীয় sunrise-এ বদলায়। তাই bar নির্ণয়ের আগে প্রশ্নটি পরিষ্কার করতে হবে: user কি একটি civil date-এর report চেয়েছেন, নাকি exact instant-এর live Panchanga state?

Date report-এর span হলো [Sunrise(D), Sunrise(D+1)) এবং bar হলো D-এর weekday। Live mode-এ local date-এর sunrise-এর সঙ্গে current UTC instant compare করে anchor date আজ বা গতকাল নির্বাচন করতে হয়। পরের sunrise কখনোই কেবল ২৪ ঘণ্টা যোগ করে বানানো উচিত নয়—বিশেষ করে DST region-এ।

Continuous JD/JDN core, explicit sunrise profile, validated location/time zone এবং half-open event interval একসঙ্গে ব্যবহার করলে Daily Details, print report, API, XML ও historical dual-calendar output একই নিয়মে স্থিতিশীল থাকে।

তথ্যসূত্র ও আরও পাঠ

  1. Positional Astronomy Centre—Rashtriya Panchang Explanation; ভারতীয় sunrise-day convention, Panchanga elements, post-midnight time এবং sunrise definition.
  2. Rashtriya Panchang—Daily Panchanga; weekday, sunrise ও daily elements-এর official presentation.
  3. U.S. Naval Observatory—Rise, Set and Twilight Definitions; standard computational sunrise-এর geometric definition.
  4. Nachum Dershowitz ও Edward M. Reingold—Indian Calendrical Calculations; critical time, sunrise, Julian day ও Indian calendar framework.
  5. Microsoft Learn—TimeZoneInfo.ConvertTime; .NET time-zone conversion reference.
  6. Microsoft Learn—DateTimeOffset; offset-bearing instant model.
  7. সূর্য সিদ্ধান্ত পঞ্জিকা project specification; sunrise-to-sunrise daily scan, Julian/Gregorian dual display ও location-specific rendering.

মন্তব্য, আলোচনা ও প্রশ্ন