📄 datelunar.c
字号:
/******************************************************************************
*
* Copyright (c) 1995-2003 PalmSource, Inc. All rights reserved.
*
* File: DateLunar.c
*
* Release: Palm OS 5 SDK (68K) R3.
*
* Description:
* This file contains the (temporary) lunar calendar support for the
* Datebook application. These routines will be part of Time Manager 6.0.
*
*****************************************************************************/
#include <PalmTypes.h>
#include <Chars.h>
#include <DateTime.h>
#include <DataMgr.h> // For DmGetResource
#include <ErrorMgr.h>
#include <MemoryMgr.h> // For memErrInvalidParam
#include <StringMgr.h> // For StrNCopy, StrIToA, etc
#include <TextMgr.h> // For TxtReplaceStr
#include <SysUtils.h> // For SysStringByIndex
#include "UIResources.h" // For strListRscType
#include "DateLunar.h"
/* Drop this in here so that the table processing code can be more easily
ported to Sahara.
*/
#ifndef BUS_ALIGN
#define BUS_ALIGN_16 16 // 16-bit data must be read/written at 16-bit address
#define BUS_ALIGN_32 32 // 32-bit data must be read/written at 32-bit address
#define BUS_ALIGN BUS_ALIGN_16
#endif
/***********************************************************************
* Private constants
**********************************************************************/
/* Resource types and IDs
*/
#define kLunarCalendarSupportedID 10200
#define kMiscStrListID 10208
#define kLunarStemsStrListID 10209
#define kLunarBranchesStrListID 10210
#define kLunarAnimalsStrListID 10211
#define kLunarMonthsStrListID 10212
#define kLunarDaysStrListID 10213
#define kLunarCalendarRscType 'luca' // Lunar calendar data
#define kChineseLunarCalendarID 19000 // Chinese lunar calendar data
/* Max length of any date template string (before expansion), excluding the null.
*/
#define maxDateTemplateLen 31
const
UInt16 kLunarCalendarDataVersion = 1;
/* Maximum substring lengths for building Chinese lunar date string
*/
#define kMaxLunarStemStrLen 15
#define kMaxLunarBranchStrLen 15
#define kMaxLunarAnimalStrLen 15
#define kMaxLunarMonthStrLen 15
#define kMaxLunarDayStrLen 15
#define kMaxLunarLeapMonthStrLen 15
/* Miscellaneous string list resource (kMiscStrListID) indexes
*/
const
UInt16 kLunarTemplateMiscStrListIndex = 0;
const
UInt16 kLunarLeapMonthMiscStrListIndex = 1;
/* Substring parameter indexes for building Chinese lunar date string
*/
const
UInt16 kLunarStemParamIndex = 0;
const
UInt16 kLunarBranchParamIndex = 1;
const
UInt16 kLunarAnimalParamIndex = 2;
const
UInt16 kLunarMonthParamIndex = 3;
const
UInt16 kLunarDayParamIndex = 4;
const
UInt16 kLunarLeapMonthParamIndex = 5;
/***********************************************************************
* Private macros
***********************************************************************/
/* Convert <inputValue> from 68K format to ARM format (or vice-versa)
and put the result in <outputValue>.
WARNING! The <inputValue> and <outputValue> arguments are evaluated more
than once, and cannot refer to the same area of memory.
*/
#define SwapBytes_(inputValue, outputValue) \
switch (sizeof(outputValue)) { \
case 1: \
outputValue = inputValue; \
break; \
case 2: \
((UInt8*)&outputValue)[0] = ((UInt8*)(&inputValue))[1]; \
((UInt8*)&outputValue)[1] = ((UInt8*)(&inputValue))[0]; \
break; \
case 4: \
((UInt8*)&outputValue)[0] = ((UInt8*)(&inputValue))[3]; \
((UInt8*)&outputValue)[1] = ((UInt8*)(&inputValue))[2]; \
((UInt8*)&outputValue)[2] = ((UInt8*)(&inputValue))[1]; \
((UInt8*)&outputValue)[3] = ((UInt8*)(&inputValue))[0]; \
break; \
}
/***********************************************************************
* Private types
**********************************************************************/
/* Description of a single month in the Chinese lunar calendar
*/
typedef struct _LunarMonthType LunarMonthType;
struct _LunarMonthType {
UInt8 monthNumber; // 1..13 (0 if unused)
UInt8 daysInThisMonth; // 29..30 (0 if unused)
};
/* Description of a single year in the Chinese solar/lunar calendar
*/
typedef struct _LunarYearType LunarYearType;
struct _LunarYearType {
Int32 yearStartDay; // Offset from 1904-1-1, -337..46409 (1903-1-29..2031-1-23)
LunarMonthType lunarMonths[timMaxChineseLunarMonths]; // Month info array (last might not be used)
};
/* Database of lunar calendar information
The complete database is (2+4+(13*2))*128=4096 bytes.
*/
typedef struct _LunarCalendarDataType LunarCalendarDataType;
struct _LunarCalendarDataType {
UInt16 version;
UInt16 lunarYearOfYearIndex0; // Position of lunarYear[0] in sexigesimal cycle 1..60
UInt16 numKnownYears; // # elements in lunarYears
LunarYearType lunarYears[1]; // Variable length record
};
/***********************************************************************
* Private forward declarations
***********************************************************************/
static LunarCalendarDataType*
PrvGetLunarCalendarP(void);
static UInt16
PrvFindLunarYearIndex(
const
LunarCalendarDataType* iLunarCalendarDataP,
Int32 iDayCount);
static Char*
PrvStringByIndex(
UInt16 iStringListID,
UInt16 iStringIndex,
Char* oResultStr,
UInt16 iMaxSize);
/***********************************************************************
* Private global variables
***********************************************************************/
static
LunarCalendarDataType* pLunarCalendarP = NULL;
/***********************************************************************/
Boolean
DateSupportsLunarCalendar(void)
/*
Return true if the system locale supports the Chinese lunar calendar.
*/
{
Boolean systemSupportsLunarCalendar
= (Boolean)ResLoadConstant(kLunarCalendarSupportedID);
return(systemSupportsLunarCalendar);
} // DateSupportsLunarCalendar
/***********************************************************************/
Err
DateSecondsToLunarDate(
UInt32 iSeconds,
UInt16* oLunarYear,
UInt16* oLunarMonth,
UInt16* oLunarDay,
Boolean* oIsLeapMonth)
/*
Convert <iSeconds> (since 1/1/1904) to the Chinese *<oLunarYear>,
*<oLunarMonth> and *<oLunarDay>. Set *<oIsLeapMonth> to true if this is
the second month in this year with *<oLunarMonth>.
*/
{
LunarCalendarDataType* chineseLunarCalendarP = NULL;
Int32 dayCount;
LunarYearType* lunarYearP = NULL;
UInt16 lunarYearIndex;
UInt16 lunarMonthIndex;
Int32 yearStartDay;
UInt16 lunarYearOfYearIndex0;
/* Initialize our outputs in case we're unsuccessful.
*/
*oLunarYear = 1;
*oLunarMonth = 1;
*oLunarDay = 1;
*oIsLeapMonth = false;
if (!DateSupportsLunarCalendar())
return(timErrNoLunarCalendarSupport);
/* Convert the input seconds to days since 1904
*/
dayCount = iSeconds / daysInSeconds;
/* Grab the lunar calendar resource
*/
chineseLunarCalendarP = PrvGetLunarCalendarP();
if (!chineseLunarCalendarP) {
ErrNonFatalDisplay("Unable to load lunar calendar data resource.");
return(timErrNoLunarCalendarSupport);
}
/* Find the year record that corresponds to this date, and calculate its
position in the sexigesimal cycle.
*/
#if BUS_ALIGN == BUS_ALIGN_32
lunarYearOfYearIndex0 = chineseLunarCalendarP->lunarYearOfYearIndex0;
#else
SwapBytes_(chineseLunarCalendarP->lunarYearOfYearIndex0, lunarYearOfYearIndex0);
#endif
lunarYearIndex = PrvFindLunarYearIndex(chineseLunarCalendarP, dayCount);
lunarYearP = ( chineseLunarCalendarP->lunarYears
+ lunarYearIndex);
*oLunarYear = ( ( ( lunarYearIndex
+ lunarYearOfYearIndex0
- timFirstChineseLunarYear)
% ( timLastChineseLunarYear
- timFirstChineseLunarYear
+ 1))
+ timFirstChineseLunarYear);
/* We now know the year, and can calculate day number within it.
*/
#if BUS_ALIGN == BUS_ALIGN_32
yearStartDay = lunarYearP->yearStartDay;
#else
SwapBytes_(lunarYearP->yearStartDay, yearStartDay);
#endif
*oLunarDay = (UInt16)(dayCount - yearStartDay);
/* Search for the correct lunar month, and calculate the lunar day.
*/
for ( lunarMonthIndex = 0;
*oLunarDay >= lunarYearP->lunarMonths[lunarMonthIndex].daysInThisMonth;
lunarMonthIndex++) {
if ( (lunarMonthIndex >= timMaxChineseLunarMonths)
|| (lunarYearP->lunarMonths[lunarMonthIndex].monthNumber == 0)
|| (lunarYearP->lunarMonths[lunarMonthIndex].daysInThisMonth == 0)) {
ErrNonFatalDisplay("Unable to find correct lunar month in lunar year.");
return(timErrNoLunarCalendarSupport);
}
(*oLunarDay) -= lunarYearP->lunarMonths[lunarMonthIndex].daysInThisMonth;
}
(*oLunarDay)++; // First day in month is returned as 1 (not 0)
/* Return its month number and whether it's a leap month
*/
*oLunarMonth = lunarYearP->lunarMonths[lunarMonthIndex].monthNumber;
*oIsLeapMonth = ( (lunarMonthIndex > 0)
&& ( lunarYearP->lunarMonths[lunarMonthIndex-1].monthNumber
== lunarYearP->lunarMonths[lunarMonthIndex].monthNumber));
return(errNone);
} // DateSecondsToLunarDate
/***********************************************************************/
Err
DateToLunarStr(
UInt16 iLunarYear,
UInt16 iLunarMonth,
UInt16 iLunarDay,
Boolean iIsLeapMonth,
Char* oLunarDateStr,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -