“একটি মাস মানে ৩০ দিন”—এটি সুবিধাজনক civil convention, astronomical সত্য নয়। বাংলা traditional solar calendar-এ মাসের boundary সূর্যের নিরয়ণ longitude-এর প্রতি ৩০° crossing-এ স্থির হয়। সূর্য সেই ৩০° arc প্রতি মাসে সমান সময়ে অতিক্রম করে না; আবার exact ingress-কে sunrise-এ শুরু হওয়া civil date-এ বসানোর সময় পূর্ণ দিনের rounding যোগ হয়। ফলে month length বছর ও method অনুযায়ী পরিবর্তিত হয়।
একটি বাংলা মাসের দুটি আলাদা দৈর্ঘ্য
“মাসের দৈর্ঘ্য” বললে প্রথমে কোন দৈর্ঘ্য বোঝানো হচ্ছে তা নির্দিষ্ট করতে হবে:
| ধরন | সংজ্ঞা | একক |
|---|---|---|
| Astronomical ingress interval | পরপর দুটি exact Saṅkrānti instant-এর ব্যবধান | Fractional days, hours, minutes |
| Civil Bengali month length | পরপর দুটি “১ তারিখ” sunrise-এর মধ্যে counted Panjika days | পূর্ণসংখ্যা: সাধারণত ২৯–৩২ দিন |
প্রথমটি একটি continuous astronomical duration; দ্বিতীয়টি human calendar-এর পূর্ণ দিনের count। Exact interval ৩০.৪২ দিন হলেও civil month ৩০ বা ৩১ দিন হতে পারে। আবার দুই প্রান্তে month-start rule-এর rounding বিপরীত দিকে গেলে civil count exact interval-এর nearest integer থেকে এক দিন দূরেও যেতে পারে।
প্রতিটি রাশি ৩০°—তবু সময় সমান নয় কেন?
Zodiac-কে ১২টি সমান ৩০° sector-এ ভাগ করা হয়:
সমান angular distance মানেই সমান travel time নয়। একটি গাড়ি একই ৩০ কিলোমিটার পথ কখনো দ্রুত, কখনো ধীরে অতিক্রম করলে সময় বদলায়। একইভাবে Sun-এর apparent longitude-এর daily rate সারা বছর সমান নয়।
যদি longitude rate ঠিক ১°/day হতো, প্রতিটি solar month ৩০ দিন হতো। বাস্তবে rate season ও model অনুযায়ী বদলে যায়। তাই ৩০° পার হতে কোথাও ২৯ দিনের একটু বেশি, কোথাও ৩১ দিনেরও বেশি সময় লাগে।
Modern astronomy: elliptical orbit ও apparent solar speed
Modern heliocentric ব্যাখ্যায় পৃথিবীর orbit ellipse; সূর্য সেই ellipse-এর এক focus-এ। Kepler-এর second law অনুযায়ী পৃথিবী perihelion-এর কাছে দ্রুত এবং aphelion-এর কাছে ধীরে চলে। পৃথিবী থেকে দেখলে Sun-এর apparent motion-ও সারা বছর সমান থাকে না।
ফলে Sun যখন zodiac-এর একটি ৩০° sector দ্রুত অতিক্রম করে, সংশ্লিষ্ট solar month ছোট হয়; ধীরে অতিক্রম করলে মাস দীর্ঘ হয়। Northern seasonal labels সরাসরি cause নয়—মূল cause orbital geometry ও longitude rate।
Surya Siddhanta model-এ অসম গতি
Traditional Surya Siddhanta engine modern Keplerian orbital elements ব্যবহার করে না। প্রথমে mean Sun সমবেগে চলে; তারপর মন্দোচ্চ ও manda equation-এর correction প্রয়োগ করে traditional true Sun পাওয়া যায়:
True Sun = Normalize(Mean Sun − Manda correction)
Manda correction position অনুযায়ী বদলায়। তাই traditional true Sun-ও zodiac-এর প্রতিটি ৩০° sector সমান সময়ে অতিক্রম করে না। Model modern astronomy থেকে আলাদা হলেও variable solar-month duration উভয় system-এই দেখা যায়।
Traditional ও Drik month length একই হওয়া বাধ্যতামূলক নয়। দুটি engine-এর ingress time কয়েক মিনিট বা ঘণ্টা ভিন্ন হলে sunrise/midnight boundary-এর কাছে civil month এক দিন ভিন্ন হতে পারে।
Exact Saṅkrānti থেকে sunrise-based month
বাংলা মাস exact ingress moment-এ civilভাবে শুরু হয় না। Bengal Rule একটি selected sunrise-কে ১ তারিখ করে:
- Sunrise থেকে midnight-এর আগে ingress → next sunrise;
- Midnight-এর পরে ingress → following sunrise;
- Midnight ±২৪ মিনিট → sunrise-tithi-end test;
- Karkaṭa ও Makara → window-এর বিশেষ rule।
প্রতিটি month boundary-তে ingress ও first-day sunrise-এর মধ্যে একটি offset তৈরি হয়। পরের month boundary-তে offset একই নাও হতে পারে। এই দুই offset-এর পার্থক্য civil month-এর day count-কে এক দিন বাড়াতে বা কমাতে পারে।
| Current month start | Next month start | Civil length tendency |
|---|---|---|
| Ingress-এর অল্প পরে sunrise | Ingress-এর অনেক পরে selected sunrise | মাস কিছুটা দীর্ঘ |
| Ingress-এর অনেক পরে selected sunrise | Ingress-এর অল্প পরে sunrise | মাস কিছুটা ছোট |
| দুই boundary-তে কাছাকাছি offset | কাছাকাছি offset | Exact interval-এর nearest day count |
Exact duration ও civil day count-এর সূত্র
Month i-এর exact astronomical duration:
= SaṅkrāntiJDᵢ₊₁ − SaṅkrāntiJDᵢ
প্রতিটি ingress-এর পরে Bengal Rule নির্বাচিত first-day sunrise পর্যন্ত offset:
= FirstDaySunriseᵢ − SaṅkrāntiInstantᵢ
দুটি selected sunrise-এর continuous difference:
= ExactDurationᵢ + StartOffsetᵢ₊₁ − StartOffsetᵢ
CivilDayCountᵢ
= SunriseIndexᵢ₊₁ − SunriseIndexᵢ
CivilDuration sunrise-to-sunrise elapsed time; CivilDayCount calendar grid-এর row count। Sunrise প্রতিদিন ঠিক ২৪ ঘণ্টা ব্যবধানে হয় না, তাই elapsed hours ও integer sunrise count আলাদা field হিসেবে রাখা ভালো।
বারো মাসের সাধারণ ২৯–৩২ দিনের pattern
Government of India Calendar Reform Committee-এর historical survey-এ traditional Surya Siddhanta–ভিত্তিক solar month-এর সাধারণ civil-length pattern নিম্নরূপ দেওয়া হয়েছে। এটি fixed schedule নয়; year ও boundary rule অনুযায়ী range-এর মধ্যে বদলাতে পারে।
| বাংলা মাস | সাধারণ civil range | Solar rāśi |
|---|---|---|
| বৈশাখ | ৩০–৩১ | মেষ |
| জ্যৈষ্ঠ | ৩১–৩২ | বৃষ |
| আষাঢ় | ৩১–৩২ | মিথুন |
| শ্রাবণ | ৩১–৩২ | কর্কট |
| ভাদ্র | ৩১–৩২ | সিংহ |
| আশ্বিন | ৩০–৩১ | কন্যা |
| কার্তিক | ২৯–৩০ | তুলা |
| অগ্রহায়ণ | ২৯–৩০ | বৃশ্চিক |
| পৌষ | ২৯–৩০ | ধনু |
| মাঘ | ২৯–৩০ | মকর |
| ফাল্গুন | ২৯–৩০ | কুম্ভ |
| চৈত্র | ৩০–৩১ | মীন |
Committee report-এর ভাষায় summer-side কিছু মাস ৩১–৩২ দিন এবং winter-side কিছু মাস ২৯–৩০ দিন হতে পারে। এই pattern printed Panjika বুঝতে সাহায্য করে, কিন্তু engine-এ table দেখে day count assign করা উচিত নয়। Start-to-next-start calculation-ই authoritative।
বারো মাস যোগ করলে বছর ৩৬৫ না ৩৬৬?
Exact traditional solar year হলো পরপর দুটি Mesha Saṅkrānti-র interval। Project research-এ ব্যবহৃত traditional-fit year length প্রায় ৩৬৫.২৫৮৭৫৬৪৮ দিন; কিন্তু first Vaiśākha sunrise থেকে পরের বছরের first Vaiśākha sunrise পর্যন্ত integer civil-day count সাধারণত ৩৬৫ বা ৩৬৬ হতে পারে।
বারোটি civil month length যোগ করলে একই দুই year-start sunrise-এর difference পাওয়ার কথা:
= NextYearFirstDayIndex − CurrentYearFirstDayIndex
এই invariant batch export-এর শক্তিশালী test। প্রতিটি month individually valid হলেও month boundary duplicate বা missing হলে বারো মাসের total mismatch করবে।
Traditional, Modern Fit ও Drik profile
| Profile | Ingress source | Month-length effect |
|---|---|---|
| Historical Surya Siddhanta | Canonical constants ও Bīja | Traditional true Sun এবং Bengal Rule |
| Modern Fit 1947+ | Month-wise star correction-সহ dedicated solar branch | Printed modern Saṅkrānti/date matching; কিছু boundary এক দিন সরে যেতে পারে |
| Drik/Lahiri | Modern ephemeris sidereal Sun | Astronomical ingress interval ও selected civil convention |
| Bangladesh official civil | Fixed administrative rules | Astronomical variable-length traditional calendar নয় |
Mode বদলালে result তুলনা করতে একই Bengali year, reference location, day-boundary rule ও output calendar label ব্যবহার করুন। শুধু “১ বৈশাখ কোন Gregorian date” তুলনা করলে ingress difference এবং rule-rounding difference আলাদা বোঝা যায় না।
Modern Fit star correction values—বৈশাখ থেকে চৈত্র: 31, 20, 23, 48, 51, 39, 33, 39, 43, 32, 30, 34—শুধু Saṅkrānti/Bengali date branch-এ প্রয়োগ হবে। Month cell-এর tithi, nakṣatra, yoga, karaṇa ও graha canonical engine-এ থাকবে।
Location কীভাবে civil month length বদলাতে পারে?
Exact geocentric Saṅkrānti UTC instant সাধারণত location-independent; কিন্তু local clock, midnight ও sunrise location অনুযায়ী বদলায়। তাই fully local Bengal Rule-এ একই ingress দুই city-তে আলাদা selected sunrise পেতে পারে।
দুটি mode আলাদা রাখুন:
- Reference-calendar mode: Bengali date ও month length Kolkata reference; user location শুধু দৈনিক সময়ে;
- Location-aware mode: month-start rule-ও selected city-এর sunrise/midnight-এ।
Footer-এ শুধু “স্থানীয় সময়” লিখলে যথেষ্ট নয়। প্রকাশ করুন: monthStartReference=Kolkata অথবা monthStartReference=selectedLocation।
Gregorian/Julian label skip মাসের দৈর্ঘ্য নয়
১৫৮২ সালে কিছু অঞ্চলে ৪ অক্টোবরের পর ১৫ অক্টোবর এবং ১৭৫২ সালে British territories-এ ২ সেপ্টেম্বরের পর ১৪ সেপ্টেম্বর এসেছে। Calendar label বাদ গেছে; physical sunrise sequence থামেনি।
যদি historical month-এর first display label “২৯ September” এবং next start “৩০ October” হয়, numeric calendar subtraction selected cutover policy অনুযায়ী misleading হতে পারে। Month length হবে counted sunrise-day index-এর difference।
| ভুল পদ্ধতি | সঠিক পদ্ধতি |
|---|---|
| Displayed Gregorian day number subtraction | Continuous JD/sunrise index subtraction |
DateTime.DaysInMonth | Current first-day sunrise → next first-day sunrise |
| Missing labels-কে missing astronomical days ধরা | Labels ও instants আলাদা field |
| Cutover month manually 10/11 দিন বাড়ানো | Display mapper-এ regional label transition |
বাংলা বছর ৯৮৯-এর earlier export error এই distinction-এর গুরুত্ব দেখায়। Historical calendar transition grid-এ special display mapping লাগতে পারে; solar-month physics বা Bengali month-start rule বদলানোর প্রয়োজন নেই।
২৭–৩৫ দিনের software guard-এর অর্থ
Project-এর BengaliCalendarGridService-এ ২৭–৩৫ দিনের range একটি defensive sanity guard হিসেবে ব্যবহার করা যেতে পারে। এটি historical Bengali month-এর normative range নয়। Expected traditional civil range ২৯–৩২ দিন; wider guard calculation/search failure ধরার জন্য কিছু margin দেয়।
| Computed length | Recommended response |
|---|---|
| ২৯–৩২ | Expected; normal validation চালান |
| ২৭–২৮ বা ৩৩–৩৫ | Do not silently publish; diagnostics ও source exception পরীক্ষা |
| <২৭ বা >৩৫ | Hard failure; likely start search, profile, label বা iteration bug |
Wide guard pass করলেই result correct নয়। ২৮ বা ৩৪ পেলে application চালিয়ে যাওয়ার আগে detailed error report তৈরি করুন:
- Current ও next Saṅkrānti JD;
- দুটি applied-rule code;
- দুটি first-day sunrise index;
- Calculation profile ও star correction;
- Location/timezone convention;
- Julian/Gregorian display mapping;
- Search bracket ও root residual।
C# implementation
Month length এক জায়গায় compute করুন এবং exact duration, sunrise count ও displayed labels আলাদা রাখুন:
public sealed class BengaliMonthSpan
{
public BengaliMonthStartResult Start { get; init; }
public BengaliMonthStartResult NextStart { get; init; }
public double ExactSankrantiDays { get; init; }
public int CivilSunriseDays { get; init; }
public TimeSpan StartOffset { get; init; }
public TimeSpan NextStartOffset { get; init; }
}
BengaliMonthSpan BuildSpan(
BengaliMonthStartResult current,
BengaliMonthStartResult next)
{
double exactDays = next.SankrantiJulianDayUt
- current.SankrantiJulianDayUt;
int civilDays = next.FirstDayIndex - current.FirstDayIndex;
if (civilDays < 27 || civilDays > 35)
throw MonthLengthFailure(current, next, exactDays, civilDays);
return new BengaliMonthSpan
{
Start = current,
NextStart = next,
ExactSankrantiDays = exactDays,
CivilSunriseDays = civilDays,
StartOffset = current.FirstDaySunrise - current.SankrantiLocal,
NextStartOffset = next.FirstDaySunrise - next.SankrantiLocal
};
}
FirstDayIndex একটি continuous sunrise-day sequence হবে; Gregorian DateTime.DayOfYear নয়। Year boundary ও historical label transition-এ DayOfYear reset বা jump করে।
Unexpected ২৮/৩৩ day result-কে automatic clamp করে ২৯/৩২ করবেন না। Clamp bug লুকিয়ে ফেলবে এবং next month-এর day numbering আরও ভুল করবে।
Calendar grid ও research report-এ কী দেখাবেন?
সাধারণ user-এর জন্য month title ও total days যথেষ্ট হতে পারে:
জুলাই–আগস্ট ২০২৬ · July–August 2026
Research details section-এ দিন:
| Field | Value type |
|---|---|
| Current Saṅkrānti | Local time, UTC ও JD |
| Next Saṅkrānti | Local time, UTC ও JD |
| Exact ingress interval | Days + hh:mm:ss |
| Current applied rule | BeforeMidnight/window/special case |
| Next applied rule | Rule code |
| Start offsets | Ingress → selected sunrise |
| Civil month length | Counted sunrise boundaries |
| Profile | Historical, Modern Fit বা Drik |
| Reference location | Name, coordinates, timezone policy |
XML-এ exact ও civil length দুটিই রাখুন:
<month bengali_year="1433"
number="4"
name="শ্রাবণ"
exact_ingress_days="31.46"
civil_sunrise_days="32"
profile="ss-modern-fit-1947-v1">
<start rule="MidnightWindowKarkata" jd_ut="..." />
<nextStart rule="BeforeMidnight" jd_ut="..." />
</month>
Validation checklist
- প্রতিটি exact ingress interval positive এবং plausible;
- বারোটি target longitude ০°, ৩০° … ৩৩০° সঠিক mapping;
- Mesha ৩৫৯°→০° unwrap;
- Current first-day sunrise index < next index;
- Civil count expected ২৯–৩২ হলে pass;
- ২৭–২৮/৩৩–৩৫ diagnostic warning;
- <২৭ বা >৩৫ hard failure with full trace;
- Month rows count =
CivilSunriseDays; - Last day number + 1 = next month day 1;
- No duplicate or missing sunrise at month boundary;
- বারো month counts-এর sum = next year start index difference;
- Historical, Modern Fit ও Drik profiles আলাদা snapshots;
- Modern Fit daily Panchanga elements অপরিবর্তিত;
- Kolkata reference ও location-aware mode স্পষ্ট;
- Dhaka/Kolkata/New York midnight-boundary cases;
- ১৫৮২ ও ১৭৫২ label gap civil count বদলায় না;
- বাংলা বছর ৯৮৯ regression;
- বাংলা বছর ১ minimum supported range;
- Exact duration ও civil count HTML/XML-এ একই source model থেকে;
- Unexpected length automatic clamp হয় না।
উপসংহার
বাংলা traditional solar month-এর দৈর্ঘ্য দুটি কারণের যৌথ ফল। প্রথমত, Sun-এর true longitude সারা বছর সমবেগে বাড়ে না; তাই সমান ৩০° zodiac sector অতিক্রমের exact সময় ভিন্ন। দ্বিতীয়ত, Bengal Rule exact ingress-কে পরবর্তী নির্বাচিত sunrise-এ বসায়; দুই consecutive boundary-এর offset difference civil day count বদলে দেয়।
এই কারণে ২৯, ৩০, ৩১ ও ৩২ দিনের মাস স্বাভাবিক। ২৯–৩২ range traditional expected result; ২৭–৩৫ শুধু defensive software guard। Calendar reform-এর skipped labels, Gregorian month length বা DateTime subtraction দিয়ে Bengali month length নির্ধারণ করা যাবে না।
সঠিক implementation current ও next Saṅkrānti, তাদের applied Bengal Rule, selected sunrise indexes এবং continuous Julian Day আলাদাভাবে সংরক্ষণ করে। এতে historical export, Modern Fit printed-calendar matching এবং Drik comparison—সব mode-এ month length ব্যাখ্যাযোগ্য ও পরীক্ষাযোগ্য থাকে।
তথ্যসূত্র ও আরও পাঠ
- Government of India—Report of the Calendar Reform Committee, Council of Scientific and Industrial Research, 1955; traditional solar-month lengths এবং regional month-start rules.
- NASA Science—Orbits and Kepler’s Laws; elliptical orbit ও perihelion/aphelion-এ পরিবর্তনশীল orbital speed.
- Robert Sewell ও Śaṅkara Bālakṛṣṇa Dīkṣita—The Indian Calendar, 1896; solar-month civil conventions.
- M. Yano ও M. Fushimi—Pancanga 3.14 program notes; traditional Surya Siddhanta calculation এবং location-specific sunrise.
- সূর্য সিদ্ধান্ত পঞ্জিকা project;
SuryaSiddhantaEngine.cs,BengaliCalendarGridService.cs, historical calendar display এবং Modern Fit correction profile.
মন্তব্য, আলোচনা ও প্রশ্ন