typedef unsigned short      WORD;
typedef unsigned long       DWORD, HANDLE;
typedef int					BOOL, BOOLEAN, errno_t;
typedef char CHAR;
typedef short SHORT;
typedef long LONG;
typedef unsigned short WCHAR;    // wc,   16-bit UNICODE character
typedef long    __time64_t, time_t;
#define NULL 0

typedef struct _SYSTEMTIME {
	WORD wYear;
	WORD wMonth;
	WORD wDayOfWeek;
	WORD wDay;
	WORD wHour;
	WORD wMinute;
	WORD wSecond;
	WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;

typedef struct _FILETIME {
	DWORD dwLowDateTime;
	DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;

typedef struct _TIME_ZONE_INFORMATION {
	LONG Bias;
	WCHAR StandardName[32];
	SYSTEMTIME StandardDate;
	LONG StandardBias;
	WCHAR DaylightName[32];
	SYSTEMTIME DaylightDate;
	LONG DaylightBias;
} TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION;

typedef struct _TIME_DYNAMIC_ZONE_INFORMATION {
	LONG Bias;
	WCHAR StandardName[32];
	SYSTEMTIME StandardDate;
	LONG StandardBias;
	WCHAR DaylightName[32];
	SYSTEMTIME DaylightDate;
	LONG DaylightBias;
	WCHAR TimeZoneKeyName[128];
	BOOLEAN DynamicDaylightTimeDisabled;
} DYNAMIC_TIME_ZONE_INFORMATION, *PDYNAMIC_TIME_ZONE_INFORMATION;

typedef const wchar_t* LPCWSTR;

struct tm
{
	int tm_sec;   // seconds after the minute - [0, 60] including leap second
	int tm_min;   // minutes after the hour - [0, 59]
	int tm_hour;  // hours since midnight - [0, 23]
	int tm_mday;  // day of the month - [1, 31]
	int tm_mon;   // months since January - [0, 11]
	int tm_year;  // years since 1900
	int tm_wday;  // days since Sunday - [0, 6]
	int tm_yday;  // days since January 1 - [0, 365]
	int tm_isdst; // daylight savings time flag
};

struct timespec
{
	time_t tv_sec;
	long tv_nsec;
};

/* Timestamps of log entries. */
struct logtime {
	struct tm       tm;
	long     usec;
};

/*
 * Data structure representing a broken-down timestamp.
 *
 * CAUTION: the IANA timezone library (src/timezone/) follows the POSIX
 * convention that tm_mon counts from 0 and tm_year is relative to 1900.
 * However, Postgres' datetime functions generally treat tm_mon as counting
 * from 1 and tm_year as relative to 1 BC.  Be sure to make the appropriate
 * adjustments when moving from one code domain to the other.
 */
struct pg_tm
{
    int         tm_sec;
    int         tm_min;
    int         tm_hour;
    int         tm_mday;
    int         tm_mon;         /* see above */
    int         tm_year;        /* see above */
    int         tm_wday;
    int         tm_yday;
    int         tm_isdst;
    long int    tm_gmtoff;
    const char *tm_zone;
};

BOOL
SystemTimeToFileTime(
	const SYSTEMTIME* lpSystemTime,
	LPFILETIME lpFileTime
);

BOOL
FileTimeToSystemTime(
	const FILETIME* lpFileTime,
	LPSYSTEMTIME lpSystemTime
);

BOOL
SystemTimeToTzSpecificLocalTime(
	const TIME_ZONE_INFORMATION* lpTimeZoneInformation,
	const SYSTEMTIME* lpUniversalTime,
	LPSYSTEMTIME lpLocalTime
);

BOOL
SystemTimeToTzSpecificLocalTimeEx(
	const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation,
	const SYSTEMTIME* lpUniversalTime,
	LPSYSTEMTIME lpLocalTime
);

BOOL
TzSpecificLocalTimeToSystemTime(
	const TIME_ZONE_INFORMATION* lpTimeZoneInformation,
	const SYSTEMTIME* lpLocalTime,
	LPSYSTEMTIME lpUniversalTime
);

BOOL
TzSpecificLocalTimeToSystemTimeEx(
	const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation,
	const SYSTEMTIME* lpLocalTime,
	LPSYSTEMTIME lpUniversalTime
);

int _wtoi(
   const wchar_t *str
);

void GetSystemTime(
	LPSYSTEMTIME lpSystemTime
);
void GetLocalTime(
	LPSYSTEMTIME lpSystemTime
);

void GetSystemTimeAsFileTime(
	LPFILETIME lpSystemTimeAsFileTime
);

__time64_t _mkgmtime64(
	struct tm* _Tm
);

__time64_t _mkgmtime(
	struct tm* const _Tm
)
{
	return _mkgmtime64(_Tm);
}

__time64_t mktime(
	struct tm* const _Tm
)
{
	return _mkgmtime64(_Tm);
}

__time64_t _time64(
	__time64_t* _Time
);

__time64_t time(
	time_t* const _Time
)
{
	return _time64(_Time);
}

int gmtime_s(
	struct tm*        _Tm,
	__time64_t const* _Time
);

BOOL
GetFileTime(
	HANDLE hFile,
	LPFILETIME lpCreationTime,
	LPFILETIME lpLastAccessTime,
	LPFILETIME lpLastWriteTime
);

struct tm *localtime_r( const time_t *timer, struct tm *buf );

/**
 * Negative Case
 * FileTimeToSystemTime is called and the return value is checked
*/
void Correct_FileTimeToSystemTime(const FILETIME* lpFileTime)
{
	SYSTEMTIME	systemTime;

	if (!FileTimeToSystemTime(lpFileTime, &systemTime))
	{
		/// handle error
		return;
	}

	/// Normal usage
}

/**
 * Positive (Out of Scope) Bug Case
 * FileTimeToSystemTime is called but no check is conducted to verify the result of the operation
*/
void AntiPattern_FileTimeToSystemTime(const FILETIME* lpFileTime)
{
	SYSTEMTIME	systemTime;

	// (out-of-scope) GeneralBug
	FileTimeToSystemTime(lpFileTime, &systemTime);
}

/**
 * Negative Case
 * SystemTimeToTzSpecificLocalTime is called and the return value is verified
*/
void Correct_SystemTimeToTzSpecificLocalTime(const TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpUniversalTime)
{
	SYSTEMTIME	localTime;

	if (!SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation, lpUniversalTime, &localTime))
	{
		/// handle error
		return;
	}

	/// Normal usage
}

/**
 * Positive (Out of Scope) Case
 * AntiPattern_SystemTimeToTzSpecificLocalTime is called but the return value is not validated
*/
void AntiPattern_SystemTimeToTzSpecificLocalTime(const TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpUniversalTime)
{
	SYSTEMTIME	localTime;

	// (out-of-scope) GeneralBug
	SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation, lpUniversalTime, &localTime);
}

/**
 * Negative Case
 * SystemTimeToTzSpecificLocalTimeEx is called and the return value is validated
*/
void Correct_SystemTimeToTzSpecificLocalTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpUniversalTime)
{
	SYSTEMTIME	localTime;

	if (!SystemTimeToTzSpecificLocalTimeEx(lpTimeZoneInformation, lpUniversalTime, &localTime))
	{
		/// handle error
		return;
	}

	/// Normal usage
}

/**
 * Positive Case
 * SystemTimeToTzSpecificLocalTimeEx is called but the return value is not validated
*/
void AntiPattern_SystemTimeToTzSpecificLocalTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpUniversalTime)
{
	SYSTEMTIME	localTime;

	// (out-of-scope) GeneralBug
	SystemTimeToTzSpecificLocalTimeEx(lpTimeZoneInformation, lpUniversalTime, &localTime);
}

/**
 * Negative Case
 * Correct use of TzSpecificLocalTimeToSystemTime, function is called and the return value is validated.
*/
void Correct_TzSpecificLocalTimeToSystemTime(const TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpLocalTime)
{
	SYSTEMTIME	universalTime;

	if (!TzSpecificLocalTimeToSystemTime(lpTimeZoneInformation, lpLocalTime, &universalTime))
	{
		/// handle error
		return;
	}

	/// Normal usage
}

/**
 * Positive (Out of Scope) Case
 * TzSpecificLocalTimeToSystemTime is called however the return value is not validated
*/
void AntiPattern_TzSpecificLocalTimeToSystemTime(const TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpLocalTime)
{
	SYSTEMTIME	universalTime;

	// (out-of-scope) GeneralBug
	TzSpecificLocalTimeToSystemTime(lpTimeZoneInformation, lpLocalTime, &universalTime);
}

/**
 * Negative Case
 * TzSpecificLocalTimeToSystemTimeEx is called and the return value is correctly validated
*/
void Correct_TzSpecificLocalTimeToSystemTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpLocalTime)
{
	SYSTEMTIME	universalTime;

	if (!TzSpecificLocalTimeToSystemTimeEx(lpTimeZoneInformation, lpLocalTime, &universalTime))
	{
		/// handle error
		return;
	}

	/// Normal usage
}

/**
 * Positive (Out of Scope) Case
 * TzSpecificLocalTimeToSystemTimeEx is called however the return value is not validated
*/
void AntiPattern_TzSpecificLocalTimeToSystemTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpLocalTime)
{
	SYSTEMTIME	universalTime;

	// (out-of-scope) GeneralBug
	TzSpecificLocalTimeToSystemTimeEx(lpTimeZoneInformation, lpLocalTime, &universalTime);
}

/*************************************************
				 SYSTEMTIME Cases
*************************************************/

/**
 * Negative Case
 * SystemTimeToFileTime is called and the return value is validated in a guard
*/
void Correct_filetime_conversion_check(SYSTEMTIME& st)
{
	FILETIME ft;

	if (!SystemTimeToFileTime(&st, &ft))
	{
		/// Something failed, handle error
		return;
	}

	/// SystemTimeToFileTime succeeded
}

//////////////////////////////////////////////

/**
 * Positive (Out of Scope) Case
 * SystemTimeToFileTime is called but the return value is not validated in a guard
*/
void AntiPattern_unchecked_filetime_conversion(SYSTEMTIME& st)
{
	FILETIME ft;

	// (out-of-scope) GeneralBug: Unchecked call to SystemTimeToFileTime. this may have failed, but we didn't check the return value!
	SystemTimeToFileTime(&st, &ft);
}

/**
 * Positive (Out of Scope) Case
 * SystemTimeToFileTime is called but the return value is not validated in a guard
*/
void AntiPattern_unchecked_filetime_conversion2(SYSTEMTIME* st)
{
	FILETIME ft;

	if (st != NULL)
	{
		// (out-of-scope) GeneralBug: Unchecked call to SystemTimeToFileTime. this may have failed, but we didn't check the return value!
		SystemTimeToFileTime(st, &ft);
	}
}

/**
 * Positive (Out of Scope)
 * SYSTEMTIME.wDay is incremented by one (and no guard exists)
*/
void AntiPattern_unchecked_filetime_conversion2()
{
	SYSTEMTIME st;
	FILETIME ft;
	GetSystemTime(&st);

	st.wDay++;

	// (out-of-scope) GeneralBug: Not checking is OK, no struct manipulation
	SystemTimeToFileTime(&st, &ft);
}

/**
 * Positive Cases
 * 	- Anti-pattern 1: [year +-n, month, day]
 * 	- Generic (Out of Scope) - UncheckedReturnValueForTimeFunctions
*/
void AntiPattern_unchecked_filetime_conversion2a()
{
	SYSTEMTIME st;
	FILETIME ft;
	GetSystemTime(&st);

	// BUG - UncheckedLeapYearAfterYearModification
	st.wYear += 2; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	// BUG - UncheckedReturnValueForTimeFunctions
	SystemTimeToFileTime(&st, &ft);
}

/**
 * Positive Cases
 * 	- Anti-pattern 1: [year +-n, month, day]
 * 	- Generic (Out of Scope) - UncheckedReturnValueForTimeFunctions
*/
void AntiPattern_unchecked_filetime_conversion2b()
{
	SYSTEMTIME st;
	FILETIME ft;
	GetSystemTime(&st);

	// BUG - UncheckedLeapYearAfterYearModification
	st.wYear++; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	// BUG - UncheckedReturnValueForTimeFunctions
	SystemTimeToFileTime(&st, &ft);
}

/**
 * Positive Cases
 * 	- Anti-pattern 1: [year +-n, month, day]
 * 	- Generic (Out of Scope) - UncheckedReturnValueForTimeFunctions
*/
void AntiPattern_unchecked_filetime_conversion2b(SYSTEMTIME* st)
{
	FILETIME ft;

	// BUG - UncheckedLeapYearAfterYearModification
	st->wYear++; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	// BUG - UncheckedReturnValueForTimeFunctions
	SystemTimeToFileTime(st, &ft);
}

/**
 * Positive Cases
 * 	- Anti-pattern 3: datetime.AddDays(+-28)
 * 	- Generic (Out of Scope) - UncheckedReturnValueForTimeFunctions
*/
void AntiPattern_unchecked_filetime_conversion3()
{
	SYSTEMTIME st;
	FILETIME ft;
	GetSystemTime(&st);

	if (st.wMonth < 12)
	{
		// Anti-pattern 3: datetime.AddDays(+-28)
		st.wMonth++;
	}
	else
	{
		// No check for leap year is required here, as the month is statically set to January.
		st.wMonth = 1;
		st.wYear++;
	}

	// (out-of-scope) GeneralBug: Not checking if newly generated date is valid for conversion
	SystemTimeToFileTime(&st, &ft);
}

//////////////////////////////////////////////

/**
 * Negative Case - Anti-pattern 1: [year +-n, month, day]
 * Year is incremented and if we are on Feb the 29th, set to the 28th if the new year is a common year.
*/
void CorrectPattern_check1()
{
	SYSTEMTIME st;
	GetSystemTime(&st);

	st.wYear++;

	// Guard against February the 29th
	if (st.wMonth == 2 && st.wDay == 29)
	{
		// move back a day when landing on Feb 29 in an non-leap year
		bool isLeapYear = st.wYear % 4 == 0 && (st.wYear % 100 != 0 || st.wYear % 400 == 0);
		if (!isLeapYear)
		{
			st.wDay = 28;
		}
	}

	// Safe to use
	AntiPattern_unchecked_filetime_conversion(st);
}

/**
 * Negative Case - Anti-pattern 1: [year +-n, month, day]
 * Years is incremented by some integer and then the leap year case is correctly guarded and handled.
*/
void CorrectPattern_check2(int yearsToAdd)
{
	SYSTEMTIME st;
	GetSystemTime(&st);

	st.wYear += yearsToAdd;

	// Guard
	bool isLeapYear = st.wYear % 4 == 0 && (st.wYear % 100 != 0 || st.wYear % 400 == 0);
	st.wDay = st.wMonth == 2 && st.wDay == 29 && !isLeapYear ? 28 : st.wDay;

	// Safe to use
	AntiPattern_unchecked_filetime_conversion(st);
}

/**
 * Could give rise to AntiPattern 7: IsLeapYear (Conditional Logic)
*/
bool isLeapYear(SYSTEMTIME& st)
{
	return st.wYear % 4 == 0 && (st.wYear % 100 != 0 || st.wYear % 400 == 0);
}

/**
 * Negative Case - Anti-pattern 1: [year +-n, month, day]
 * Years is incremented by some integer and then the leap year case is correctly guarded and handled.
*/
void CorrectPattern_check3()
{
	SYSTEMTIME st;
	GetSystemTime(&st);

	st.wYear++;

	// Guard
	/** Negative Case - Anti-pattern 7: IsLeapYear
 	* Body of conditional statement is safe recommended code
	*/
	if (st.wMonth == 2 && st.wDay == 29 && isLeapYear(st))
	{
		// move back a day when landing on Feb 29 in an non-leap year
		st.wDay = 28;
	}

	// Safe to use
	AntiPattern_unchecked_filetime_conversion(st);
}

/**
 * Could give rise to AntiPattern 7: IsLeapYear (Conditional Logic)
*/
bool isLeapYear2(int year)
{
	return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}

bool fixDate(int day, int month, int year)
{
	return (month == 2 && day == 29 && isLeapYear2(year));
}

/**
 * Negative Case - Anti-pattern 1: [year +-n, month, day]
 * Years is incremented by some integer and then the leap year case is correctly guarded and handled.
*/
void CorrectPattern_check4()
{
	SYSTEMTIME st;
	GetSystemTime(&st);

	///// FP
	st.wYear++;

	// Guard
	/** Negative Case - Anti-pattern 7: IsLeapYear
 	* Body of conditional statement is safe recommended code
	*/
	if (fixDate(st.wDay, st.wMonth, st.wYear))
	{
		// move back a day when landing on Feb 29 in an non-leap year
		st.wDay = 28; // GOOD [FALSE POSITIVE] Anti-pattern 7
	}

	// Safe to use
	AntiPattern_unchecked_filetime_conversion(st);
}

/**
 * Negative Case - Generic
 * No manipulation is conducted on struct populated from GetSystemTime.
*/
void CorrectPattern_NotManipulated_DateFromAPI_0()
{
	SYSTEMTIME st;
	GetSystemTime(&st);
	FILETIME ft;

	// Not checking is OK, no struct manipulation
	SystemTimeToFileTime(&st, &ft);
}

/**
 * Negative Case - Generic
 * No manipulation is conducted on struct populated from GetFileTime.
*/
void CorrectPattern_NotManipulated_DateFromAPI_1(HANDLE hWatchdog)
{
	SYSTEMTIME st;
	FILETIME ft;

	GetFileTime(hWatchdog, NULL, NULL, &ft);
	FileTimeToSystemTime(&ft, &st);
}

/////////////////////////////////////////////////////////////////

/**
 * Negative Case - Anti-pattern 1: [year +-n, month, day]
 * Year is incremented by some integer and checked through a conversion through an inter procedural function check
*/
void AntiPattern_1_year_addition()
{
	SYSTEMTIME st;
	GetSystemTime(&st);

	// Safe, checked interprocedurally through Correct_filetime_conversion_check
	st.wYear++;

	// Usage of potentially invalid date
	Correct_filetime_conversion_check(st);
}



/**
 * Negative Case - Anti-pattern 1: [year +-n, month, day]
 * Years is incremented by some integer and checked through a conversion through an inter procedural function check
*/
void AntiPattern_simple_addition(int yearAddition)
{
	SYSTEMTIME st;

	GetSystemTime(&st);

	st.wYear += yearAddition;

	// Usage of potentially invalid date
	Correct_filetime_conversion_check(st);
}

/**
 * Positive Case - Anti-pattern 1: [year +-n, month, day]
 * Years is incremented by some integer but a leap year is not handled *correctly*.
*/
void AntiPattern_IncorrectGuard(int yearsToAdd)
{
	SYSTEMTIME st;
	GetSystemTime(&st);

	// BUG - UncheckedLeapYearAfterYearModification
	st.wYear += yearsToAdd; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	// Incorrect Guard
	if (st.wMonth == 2 && st.wDay == 29)
	{
		// Part of a different anti-pattern (AntiPattern 5).
		// Make sure the guard includes the proper check
		bool isLeapYear = st.wYear % 4 == 0;
		if (!isLeapYear)
		{
			st.wDay = 28;
		}
	}
}

/*************************************************
				struct tm Cases
*************************************************/

void CorrectUsageOf_mkgmtime(struct tm& timeinfo)
{
	if (_mkgmtime(&timeinfo) == -1)
	{
		/// Something failed, handle error
		return;
	}

	/// _mkgmtime succeeded
}

/**
 * Positive Case - General (Out of Scope)
 * Must Check for return value of _mkgmtime
*/
void AntiPattern_uncheckedUsageOf_mkgmtime(struct tm& timeinfo)
{
	// (out-of-scope) GeneralBug: Must check return value for _mkgmtime
	// QLNOTE: Include other related _mkgmtime* functions in the function name pattern
	_mkgmtime(&timeinfo);
	// _mktime64(&timeinfo);
	// _mktime32(&timeinfo);
}

//////////////////////////////////////////////////////////

/**
 * Negative Case - Anti-pattern 1: [year +-n, month, day]
 * Years is incremented by some integer and leap year is not handled correctly.
*/
void Correct_year_addition_struct_tm()
{
	time_t rawtime;
	struct tm timeinfo;
	time(&rawtime);
	// NOTE: Should ideally check return value for this function (not in scope)
	errno_t err = gmtime_s(&timeinfo, &rawtime);
	if (err)
	{
		/// handle error
		return;
	}

	// this is the potentially dangerous part, when not followed up with leap year checks
	timeinfo.tm_year++;

	// Guard
	// move back a day when landing on Feb 29 in an non-leap year
	bool isLeapYear = timeinfo.tm_year % 4 == 0 && (timeinfo.tm_year % 100 != 0 || (timeinfo.tm_year + 1900) % 400 == 0);
	timeinfo.tm_mday = timeinfo.tm_mon == 1 && timeinfo.tm_mday == 29 && !isLeapYear ? 28 : timeinfo.tm_mday;

	// safe to use
	AntiPattern_uncheckedUsageOf_mkgmtime(timeinfo);
}

/**
 * Positive Case - Anti-pattern 1: [year +-n, month, day]
 * Years is incremented by some integer and leap year is not handled correctly.
*/
void Incorrect_LinuxPattern()
{
	time_t rawtime;
	struct tm timeinfo;
	time(&rawtime);
	// NOTE: Should ideally check return value for this function (not in scope)
	errno_t err = gmtime_s(&timeinfo, &rawtime);

	/* from 1900 -> from 1980 */
	// BUG - UncheckedLeapYearAfterYearModification
	timeinfo.tm_year -= 80;
	/* 0~11 -> 1~12 */
	timeinfo.tm_mon++;
	/* 0~59 -> 0~29(2sec counts) */
	timeinfo.tm_sec >>= 1;

	// safe to use
	AntiPattern_uncheckedUsageOf_mkgmtime(timeinfo);
}

//////////////////////////////////////////

/**
 * Negative Case - Anti-pattern 1: [year +-n, month, day]
 * Years is incremented by some integer and leap year is assumed checked through
 * check of a conversion functions return value.
*/
void AntiPattern_year_addition_struct_tm()
{
	time_t rawtime;
	struct tm timeinfo;
	time(&rawtime);
	gmtime_s(&timeinfo, &rawtime);
	timeinfo.tm_year++;

	// mkgmtime result checked in nested call here, assume leap year conversion is potentially handled
	CorrectUsageOf_mkgmtime(timeinfo);
}

/////////////////////////////////////////////////////////


/**
 * Positive Case - Anti-pattern 1: [year +-n, month, day]
*/
void test(int x)
{
	struct tm timeinfo;
	SYSTEMTIME st;

	timeinfo.tm_year = x;

	// BUG - UncheckedLeapYearAfterYearModification
	// Positive Case - Anti-pattern 1: [year +-n, month, day]
	timeinfo.tm_year = x + timeinfo.tm_year;	// $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	st.wYear = x;
	// BUG - UncheckedLeapYearAfterYearModification
	// Positive Case - Anti-pattern 1: [year +-n, month, day]
	st.wYear = x + st.wYear;  // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}

/**
 * Positive AntiPattern 1 NOTE: historically considered positive but mktime checks year validity, needs re-assessment
 * Year field is modified but via an intermediary variable.
*/
void tp_intermediaryVar(struct timespec now, struct logtime &timestamp_remote)
{
	struct tm tm_parsed;

	struct tm tm_now;
	time_t t_now;
	int year;

	/*
	 * As the timestamp does not contain the year
	 * number, daylight saving time information, nor
	 * a time zone, attempt to infer it. Due to
	 * clock skews, the timestamp may even be part
	 * of the next year. Use the last year for which
	 * the timestamp is at most one week in the
	 * future.
	 *
	 * This loop can only run for at most three
	 * iterations before terminating.
	 */
	t_now = now.tv_sec;
	localtime_r(&t_now, &tm_now);

	timestamp_remote.tm = tm_parsed;
	timestamp_remote.tm.tm_isdst = -1;
	timestamp_remote.usec = now.tv_nsec * 0.001;
	for (year = tm_now.tm_year + 1;; --year)
	{
		// assert(year >= tm_now.tm_year - 1);
		timestamp_remote.tm.tm_year = year;
		if (mktime(&timestamp_remote.tm) < t_now + 7 * 24 * 60 * 60)
			break;
	}
}


	// False positive
	inline void
	IncrementMonth(LPSYSTEMTIME pst)
	{
		if (pst->wMonth < 12)
		{
			pst->wMonth++;
		}
		else
		{
			pst->wMonth = 1;
			pst->wYear++;
		}
	}

	/////////////////////////////////////////////////////////

	void mkDateTest(int year)
	{
		struct tm t;

		t.tm_sec = 0;
		t.tm_min = 0;
		t.tm_hour = 0;
		t.tm_mday = 1; // day of the month - [1, 31]
		t.tm_mon = 0;  // months since January - [0, 11]
		if (year >= 1900)
		{
			// 4-digit year
			t.tm_year = year - 1900; // GOOD
		}
		else if ((year >= 0) && (year < 100))
		{
			// 2-digit year assumed in the range 2000 - 2099
			t.tm_year = year + 100; // GOOD [FALSE POSITIVE]
		}
		else
		{
			// fail
		}
		// ...
	}

	/**
	 * Negative Case - Anti-pattern 1a: [a.year, b.month, b.day]
	 * False positive: No modification of SYSTEMTIME struct.
	 */
	void unmodified1()
	{
		SYSTEMTIME st;
		FILETIME ft;
		WORD w;

		GetSystemTime(&st);

		w = st.wYear;

		SystemTimeToFileTime(&st, &ft); // GOOD - no modification
	}

	/**
	 * Negative Case - Anti-pattern 1a: [a.year, b.month, b.day]
	 * False positive: No modification of SYSTEMTIME struct.
	 */
	void unmodified2()
	{
		SYSTEMTIME st;
		FILETIME ft;
		WORD *w_ptr;

		GetSystemTime(&st);

		w_ptr = &(st.wYear);

		SystemTimeToFileTime(&st, &ft); // GOOD - no modification
	}

	/**
	 * Positive Case - Anti-pattern 1: [year +-n, month, day]
	 * Modification of SYSTEMTIME struct adding to year but no leap year guard is conducted.
	 */
	void modified3()
	{
		SYSTEMTIME st;
		FILETIME ft;
		WORD *w_ptr;

		GetSystemTime(&st);

		// BUG - UncheckedLeapYearAfterYearModification
		st.wYear = st.wYear + 1; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

		SystemTimeToFileTime(&st, &ft);
	}

	/**
	 * Positive Case - Anti-pattern 1: [year +-n, month, day]
	 * Modification of SYSTEMTIME struct adding to year but no leap year guard is conducted.
	 */
	void modified4()
	{
		SYSTEMTIME st;
		FILETIME ft;
		WORD *w_ptr;

		GetSystemTime(&st);

		// BUG - UncheckedLeapYearAfterYearModification
		st.wYear++; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

		SystemTimeToFileTime(&st, &ft);
	}

	/**
	 * Negative Case - Anti-pattern 1: [year +-n, month, day]
	 * Modification of SYSTEMTIME struct adding to year but value passed to a
	 * conversion function that can be checked for success, and the result is checked.
	 */
	void modified5()
	{
		SYSTEMTIME st;
		FILETIME ft;
		WORD *w_ptr;

		GetSystemTime(&st);

		st.wYear++;

		// Presumed safe usage, as if the conversion is incorrect, a user can handle the error.
		// NOTE: it doesn't mean the user actually does the correct conversion and it it also
		// doesn't mean it will error our in all cases that may be invalid.
		// For example, if a leap year and the date is 28, we may want 29 if the time is meant
		// to capture the end of the month, but 28 is still valid and will not error out.
		if (SystemTimeToFileTime(&st, &ft))
		{
			///...
		}
	}

/**
* Negative Case - Anti-pattern 1: [year +-n, month, day]
* Modification of SYSTEMTIME struct by copying from another struct, but no arithmetic is performed.
*/
bool
FMAPITimeToSysTimeW(LPCWSTR wszTime, SYSTEMTIME *psystime)
{
	// if (!wszTime || SafeIsBadReadPtr(wszTime, 1) || lstrlenW(wszTime) != cchMAPITime)
	// 	return false;
	// AssertTag(!SafeIsBadWritePtr(psystime, sizeof(SYSTEMTIME)), 0x0004289a /* tag_abc80 */);
	// memset(psystime, 0, sizeof(SYSTEMTIME));

	psystime->wYear = (WORD)_wtoi(wszTime);
	psystime->wMonth = (WORD)_wtoi(wszTime+5);
	psystime->wDay = (WORD)_wtoi(wszTime+8);
	psystime->wHour = (WORD)_wtoi(wszTime+11);
	psystime->wMinute = (WORD)_wtoi(wszTime+14);
	return true;
}

/**
* Negative Case - Anti-pattern 1: [year +-n, month, day]
* Modification of SYSTEMTIME struct by copying from another struct, but no arithmetic is performed.
*/
void fp_daymonth_guard(){
	SYSTEMTIME st;
	FILETIME ft;
	GetSystemTime(&st);
    // FALSE POSITIVE: year is incremented but month is checked and day corrected
	// in a ternary operation. It may be possible to fix this with a more sophisticated
	// data flow analysis.
	st.wYear++; // $ SPURIOUS: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	st.wDay = st.wMonth == 2 && st.wDay == 29 ? 28 : st.wDay;

	SystemTimeToFileTime(&st, &ft);
}

void increment_arg(WORD &x){
	x++; // $ Source
}

void increment_arg_by_pointer(WORD *x){
	(*x)++; // $ Source
}


void fn_year_set_through_out_arg(){
	SYSTEMTIME st;
	GetSystemTime(&st);
	// BAD, year incremented without check
	increment_arg(st.wYear); // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	// GetSystemTime(&st);
	// Bad, year incremented without check
	increment_arg_by_pointer(&st.wYear); // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}


/* TODO: don't alert on simple copies from another struct where all three {year,month,day} are copied
void
GetEpochTime(struct pg_tm *tm)
{
	struct pg_tm *t0;
	pg_time_t	epoch = 0;

	t0 = pg_gmtime(&epoch);

	tm->tm_year = t0->tm_year;
	tm->tm_mon = t0->tm_mon;
	tm->tm_mday = t0->tm_mday;
	tm->tm_hour = t0->tm_hour;
	tm->tm_min = t0->tm_min;
	tm->tm_sec = t0->tm_sec;

	tm->tm_year += 1900;
	tm->tm_mon++;
} */

void
fp_guarded_by_month(struct pg_tm *tm){
	int woy = 52;
	int MONTHS_PER_YEAR = 12;
	/*
	* If it is week 52/53 and the month is January, then the
	* week must belong to the previous year. Also, some
	* December dates belong to the next year.
	*/
	if (woy >= 52 && tm->tm_mon == 1)
		--tm->tm_year; // Negative Test Case
	if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
		++tm->tm_year; // Negative Test Case
}

typedef unsigned short CSHORT;

typedef struct _TIME_FIELDS {
  CSHORT Year;
  CSHORT Month;
  CSHORT Day;
  CSHORT Hour;
  CSHORT Minute;
  CSHORT Second;
  CSHORT Milliseconds;
  CSHORT Weekday;
} TIME_FIELDS, *PTIME_FIELDS;

void
tp_ptime(PTIME_FIELDS ptm){
	ptm->Year = ptm->Year - 1; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}


bool isLeapYearRaw(WORD year)
{
	return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}

void leap_year_checked_raw_false_positive1(WORD year, WORD offset, WORD day){
	struct tm tmp;

	year += offset;

	if (isLeapYearRaw(year)){
		// in this simplified example, assume the logic of this function
		// can assume a day is 28 by default
		// this check is more to establish the leap year guard is present
		day += 1;
	}

	// Assume the check handled leap year correctly
	tmp.tm_year = year; // GOOD
	tmp.tm_mday = day;
}


void leap_year_checked_raw_false_positive2(WORD year, WORD offset, WORD day){
	struct tm tmp;

	year += offset;

	tmp.tm_year = year; // GOOD, check performed immediately after on raw year

	// Adding some additional checks to resemble cases observed in the wild
	if ( day > 0)
	{
		if (isLeapYearRaw(year)){
			// Assume logic that would adjust the day correctly
		}
	}
	else{
		if (isLeapYearRaw(year)){
			// Assume logic that would adjust the day correctly
		}
	}

	tmp.tm_mday = day;

	year += offset; // $ Source

	tmp.tm_year = year; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

}


bool isNotLeapYear(struct tm tm)
{
	return !(tm.tm_year % 4 == 0 && (tm.tm_year % 100 != 0 || tm.tm_year % 400 == 0));
}

bool isNotLeapYear2(struct tm tm)
{
	return (tm.tm_year % 4 != 0 || (tm.tm_year % 100 == 0 && tm.tm_year % 400 != 0));
}


void inverted_leap_year_check(WORD year, WORD offset, WORD day){
	struct tm tmp;

	tmp.tm_year = year + offset;

	if (isNotLeapYear(tmp)){
		day = 28;
	}

	tmp.tm_year = year + offset;

	if(isNotLeapYear2(tmp)){
		day = 28;
	}


	tmp.tm_year = year + offset;
	bool isNotLeapYear = (tmp.tm_year % 4 != 0 || (tmp.tm_year % 100 == 0 && tmp.tm_year % 400 != 0));

	if(isNotLeapYear){
		day = 28;
	}

	tmp.tm_year = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}


void simplified_leap_year_check1(WORD year, WORD offset){
	struct tm tmp;

	tmp.tm_year = year + offset;  // OK

	bool isLeap = (!((tmp.tm_year + 1900) % 4)) && ((tmp.tm_year + 1900) % 100 || !((tmp.tm_year + 1900) % 400));
	if(isLeap){
		// do something
	}

	// Modified after check, could be dangerous
	tmp.tm_year = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}

void simplified_leap_year_check2(WORD year, WORD offset){
	struct tm tmp;

	tmp.tm_year = year + offset; // OK

	bool isNotLeap = ((tmp.tm_year + 1900) % 4) || (!((tmp.tm_year + 1900) % 100) && ((tmp.tm_year + 1900) % 400));
	if(isNotLeap){
		// do something
	}

	// Modified after check, could be dangerous
	tmp.tm_year = year + offset;  // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}

void simplified_leap_year_check3(WORD year, WORD offset){
	SYSTEMTIME tmp;

	tmp.wYear = year + offset; // OK

	bool isLeap = (!(tmp.wYear % 4)) && (tmp.wYear % 100 || !(tmp.wYear% 400));
	if(isLeap){
		// do something
	}

	// Modified after check, could be dangerous
	tmp.wYear = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}

void simplified_leap_year_check4(WORD year, WORD offset){
	SYSTEMTIME tmp;

	tmp.wYear = year + offset; // OK

	bool isNotLeap = (tmp.wYear % 4) || (!(tmp.wYear % 100) && (tmp.wYear % 400));
	if(isNotLeap){
		// do something
	}

	// Modified after check, could be dangerous
	tmp.wYear = year + offset;  // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}

void bad_simplified_leap_year_check1(WORD year, WORD offset){
	struct tm tmp;

	tmp.tm_year = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	// incorrect logic, should negate the %4 result
	bool isLeap = ((tmp.tm_year + 1900) % 4) && ((tmp.tm_year + 1900) % 100 || !((tmp.tm_year + 1900) % 400));
	if(isLeap){
		// do something
	}
}

void bad_simplified_leap_year_check2(WORD year, WORD offset){
	struct tm tmp;

	tmp.tm_year = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]


	// incorrect logic, should not negate the %4 result
	bool isNotLeap = (!((tmp.tm_year + 1900) % 4)) || (!((tmp.tm_year + 1900) % 100) && ((tmp.tm_year + 1900) % 400));
	if(isNotLeap){
		// do something
	}
}

void bad_simplified_leap_year_check3(WORD year, WORD offset){
	SYSTEMTIME tmp;

	tmp.wYear = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	// incorrect logic, should negate the %4 result
	bool isLeap = (tmp.wYear % 4) && (tmp.wYear % 100 || !(tmp.wYear % 400));
	if(isLeap){
		// do something
	}
}

void bad_simplified_leap_year_check4(WORD year, WORD offset){
	SYSTEMTIME tmp;

	tmp.wYear = year + offset; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]


	// incorrect logic, should not negate the %4 result
	bool isNotLeap = (!(tmp.wYear % 4)) || (!(tmp.wYear % 100) && (tmp.wYear % 400));
	if(isNotLeap){
		// do something
	}
}


void compound_leap_year_check(WORD year, WORD offset, WORD month, WORD day){
	struct tm tmp;

	tmp.tm_year = year + offset;

	bool isLeap = tmp.tm_year % 4 == 0 && (tmp.tm_year % 100 != 0 || tmp.tm_year % 400 == 0) && (month == 2 && day == 29);

	if(isLeap){
		// do something
	}
	tmp.tm_mday = day;
	tmp.tm_mon = month;
}

void indirect_time_conversion_check(WORD year, WORD offset){
	SYSTEMTIME tmp;

	tmp.wYear = year + offset;

	FILETIME ft;

	// (out-of-scope) GeneralBug: Unchecked call to SystemTimeToFileTime. this may have failed, but we didn't check the return value!
	BOOL res = SystemTimeToFileTime(&tmp, &ft);

	// Assume this check of the result is sufficient as an implicit leap year check.
	bool x = (res == 0) ? true : false;
}

void set_time(WORD year, WORD month, WORD day){
	SYSTEMTIME tmp;

	tmp.wYear = year; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
	tmp.wMonth = month;
	tmp.wDay = day;
}

void constant_month_on_year_modification1(WORD year, WORD offset, WORD month){
	SYSTEMTIME tmp;

	if(month++ > 12){
		tmp.wMonth = 1;
		tmp.wYear = year + 1;// OK since the year is incremented with a known non-leap year month change
	}

	if(month++ > 12){

		set_time(year+1, 1, 31);// OK since the year is incremented with a known non-leap year month change
	}
}

void constant_month_on_year_modification2(WORD year, WORD offset, WORD month){
	SYSTEMTIME tmp;

	if(month++ > 12){
		tmp.wMonth = 1;
		tmp.wYear = year + 1;// OK since the year is incremented with a known non-leap year month change
	}


	if(month++ > 12){
		// some heuristics to detect a false positive here rely on variable names
		// which is often consistent in the wild.
		// This variant uses the variable names yeartmp and monthtmp
		WORD yeartmp;
		WORD monthtmp;
		yeartmp = year + 1;
		monthtmp = 1;
		set_time(yeartmp, monthtmp, 31);// OK since the year is incremented with a known non-leap year month change
	}
}

typedef struct parent_struct {
	SYSTEMTIME t;
} PARENT_STRUCT;



void nested_time_struct(WORD year, WORD offset){
	PARENT_STRUCT ps;

	ps.t.wYear = year + offset; // OK, checked below

	bool isLeap = isLeapYearRaw(ps.t.wYear);

	if(isLeap){
		// do something
	}
}

void intermediate_time_struct(WORD year, WORD offset){
	SYSTEMTIME tm, tm2;
	FILETIME ftTime;

	tm.wYear = year + offset;

	tm2.wYear = tm.wYear;


	while ( !SystemTimeToFileTime( &tm2, &ftTime ) )
	{
		/// handle error
	}

}

void constant_day_on_year_modification1(WORD year, WORD offset, WORD month){
	SYSTEMTIME tmp;

	if(month++ > 12){
		tmp.wDay = 1;
		tmp.wYear = year + 1;// OK since the year is incremented with a known non-leap year day
	}

	if(month++ > 12){

		set_time(year+1, month, 1);// OK since the year is incremented with a known non-leap year day
	}

	if(month++ > 12){

		// BAD, year incremented, month unknown in block, and date is set to 31
		// which is dangerous.
		set_time(year+1, month, 31);// $ Source
	}
}

void constant_day_on_year_modification2(WORD year, WORD month){
	SYSTEMTIME tmp;

	// FLASE POSITIVE SOURCE:
	// flowing into set_time, the set time does pass a constant day
	// but the source here and the source of that constant month don't align
	// Current heuristics require the source of the constant day align with the
	// source and/or the sink of the year modification.
	// We could potentially improve this by checking the paths of both the year and day
	// flows, but this may be more complex than is warranted for now.
	year = year + 1; // $ SPURIOUS: Source

	if(month++ > 12){
		tmp.wDay = 1;
		tmp.wYear = year;// OK since the year is incremented with a known non-leap year day
	}

	if(month++ > 12){

		set_time(year, month, 1);// OK since the year is incremented with a known non-leap year day
	}

	year = year + 1; // $ Source

	if(month++ > 12){

		// BAD, year incremented, month unknown in block, and date is set to 31
		// which is dangerous.
		set_time(year, month, 31);
	}
}


void modification_after_conversion1(tm timeinfo){
	// convert a tm year into a civil year, then modify after conversion
	// This case shows a false negative where the year might be used and it is incorrectly modified,
	// and never reassigned to another struct.
	WORD year = timeinfo.tm_year + 1900;

	year += 1; // $ MISSING: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}

WORD get_civil_year(tm timeinfo){
	return timeinfo.tm_year + 1900;
}

void modification_after_conversion2(tm timeinfo){
	// convert a tm year into a civil year, then modify after conversion
	// This case shows a false negative where the year might be used and it is incorrectly modified,
	// and never reassigned to another struct.
	WORD year = get_civil_year(timeinfo);
	year += 1; // $ MISSING: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}

void modification_after_conversion_saved_to_other_time_struct1(tm timeinfo){
	// convert a tm year into a civil year, then modify after conversion
	// This case shows a false negative where the year might be used and it is incorrectly modified,
	// and never reassigned to another struct.
	WORD year = timeinfo.tm_year + 1900;

	year += 1; // $ MISSING: Source

	SYSTEMTIME s;
	// FALSE NEGATIVE: missing this because the conversion happens locally before
	// the year adjustment, which seems as though it is part of a conversion itself
	s.wYear = year; // $ MISSING: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}



void modification_after_conversion_saved_to_other_time_struct2(tm timeinfo){
	// convert a tm year into a civil year, then modify after conversion
	// This case shows a false negative where the year might be used and it is incorrectly modified,
	// and never reassigned to another struct.
	WORD year = get_civil_year(timeinfo);

	year += 1; // $ Source

	SYSTEMTIME s;
	s.wYear = year; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}

void modification_after_conversion_saved_to_other_time_struct3(tm timeinfo){
	// convert a tm year into a civil year, then modify after conversion
	// This case shows a false negative where the year might be used and it is incorrectly modified,
	// and never reassigned to another struct.
	WORD year = timeinfo.tm_year + 1900;

	year = year + 1; // $ MISSING: Source

	SYSTEMTIME s;
	// FALSE NEGATIVE: missing this because the conversion happens locally before
	// the year adjustment, which seems as though it is part of a conversion itself
	s.wYear = year; // $ MISSING: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}


void year_saved_to_variable_then_modified1(tm timeinfo){
	// A modified year is not directly assigned to the year, rather, the year is
	// saved to a variable, modified, used, but never assigned back.
	WORD year = timeinfo.tm_year;

	// NOTE: should we even try to detect cases like this?
	// Our current rationale is that a year in a struct is more dangerous than a year in isolation
	// A year in isolation is harder to interpret
	year += 1; // MISSING: $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
}

void modification_before_conversion1(tm timeinfo){
	timeinfo.tm_year += 1; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
	// convert a tm year into a civil year, then modify after conversion
	// This case shows a false negative where the year might be used and it is incorrectly modified,
	// and never reassigned to another struct.
	WORD year = timeinfo.tm_year + 1900;
}

void modification_before_conversion2(tm timeinfo){
	timeinfo.tm_year += 1; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]
	// convert a tm year into a civil year, then modify after conversion
	// This case shows a false negative where the year might be used and it is incorrectly modified,
	// and never reassigned to another struct.
	WORD year = get_civil_year(timeinfo);
}



void year_saved_to_variable_then_modified_with_leap_check1(tm timeinfo){
	// A modified year is not directly assigned to the year, rather, the year is
	// saved to a variable, modified, used, but never assigned back.
	WORD year = timeinfo.tm_year;

	year += 1;

	// performing a check is considered good enough, even if not used correctly
	bool b = (year+1900) % 4 == 0 && ((year+1900) % 100 != 0 || (year+1900) % 400 == 0);
}


void modification_after_conversion_with_leap_check1(tm timeinfo){
	// convert a tm year into a civil year, then modify after conversion
	// This case shows a false negative where the year might be used and it is incorrectly modified,
	// and never reassigned to another struct.
	WORD year = timeinfo.tm_year + 1900;

	year += 1;

	// performing a check is considered good enough, even if not used correctly
	bool b = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}

void modification_after_conversion_with_leap_check2(tm timeinfo){
	// convert a tm year into a civil year, then modify after conversion
	// This case shows a false negative where the year might be used and it is incorrectly modified,
	// and never reassigned to another struct.
	WORD year = get_civil_year(timeinfo);

	year += 1;

	// performing a check is considered good enough, even if not used correctly
	bool b = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}

void modification_before_conversion_with_leap_check1(tm timeinfo){
	timeinfo.tm_year += 1;
	// convert a tm year into a civil year, then modify after conversion
	// This case shows a false negative where the year might be used and it is incorrectly modified,
	// and never reassigned to another struct.
	WORD year = timeinfo.tm_year + 1900;

	// performing a check is considered good enough, even if not used correctly
	bool b = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}

void modification_before_conversion_with_leap_check2(tm timeinfo){
	timeinfo.tm_year += 1;
	// convert a tm year into a civil year, then modify after conversion
	// This case shows a false negative where the year might be used and it is incorrectly modified,
	// and never reassigned to another struct.
	WORD year = get_civil_year(timeinfo);

	// performing a check is considered good enough, even if not used correctly
	bool b = (year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0);
}

void odd_leap_year_check1(tm timeinfo){
	timeinfo.tm_year += 1;


	// Using an odd sytle of checking divisible by 4 presumably as an optimization trick
	if(((timeinfo.tm_year+1900) & 3) == 0 && ((timeinfo.tm_year+1900) % 100 != 0 || (timeinfo.tm_year+1900) % 400 == 0))
	{
		// do something
	}
}

void odd_leap_year_check2(tm timeinfo){
	timeinfo.tm_year += 1; // $ SPURIOUS: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	// Using an odd sytle of checking divisible by 4 presumably as an optimization trick
	// but also check unrelated conditions on the year as an optimization to rule out irrelevant years
	// for gregorian leap years
	if(timeinfo.tm_mon == 2 && ((timeinfo.tm_year+1900) & 3) == 0 && ((timeinfo.tm_year+1900) <= 1582 || (timeinfo.tm_year+1900) % 100 != 0 || (timeinfo.tm_year+1900) % 400 == 0))
	{
		// do something
	}
}

void odd_leap_year_check3(tm timeinfo){
	timeinfo.tm_year += 1; // $ SPURIOUS: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	// Using an odd sytle of checking divisible by 4 presumably as an optimization trick
	// but also check unrelated conditions on the year as an optimization to rule out irrelevant years
	// for gregorian leap years
	if(timeinfo.tm_mon == 2 && ((timeinfo.tm_year+1900) % 4) == 0 && ((timeinfo.tm_year+1900) <= 1582 || (timeinfo.tm_year+1900) % 100 != 0 || (timeinfo.tm_year+1900) % 400 == 0))
	{
		// do something
	}
}

void odd_leap_year_check4(tm timeinfo){
	timeinfo.tm_year += 1;
	WORD year = timeinfo.tm_year + 1900;

	if( (year % 4 == 0) && (year % 100 > 0 || (year % 400 == 0)))
	{
		// do something
	}
}

void odd_leap_year_check5(tm timeinfo){
	timeinfo.tm_year += 1;
	WORD year = timeinfo.tm_year + 1900;

	if( (year % 4 > 0) || (year % 100 == 0 && (year % 400 > 0)))
	{
		// do something
	}
}


void date_adjusted_through_mkgmtime(tm timeinfo){
	timeinfo.tm_year += 1; // $ SPURIOUS: Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	// Using an odd sytle of checking divisible by 4 presumably as an optimization trick
	// but also check unrelated conditions on the year as an optimization to rule out irrelevant years
	// for gregorian leap years
	if(timeinfo.tm_mon == 2 && ((timeinfo.tm_year+1900) % 4) == 0 && ((timeinfo.tm_year+1900) <= 1582 || (timeinfo.tm_year+1900) % 100 != 0 || (timeinfo.tm_year+1900) % 400 == 0))
	{
		// do something
	}
}

bool data_killer(WORD *d){
	(*d) = 1;
	return true;
}

void interproc_data_killer1(tm timeinfo, WORD delta){
	WORD year = delta + 1;

	if(data_killer(&year)){
		timeinfo.tm_year = year;
	}
}


void leap_year_check_after_normalization(tm timeinfo, WORD delta){
	WORD year = delta + 1;

	if(data_killer(&year)){
		timeinfo.tm_year = year;
	}
}


void leap_year_check_call_on_conversion1(tm timeinfo){
	timeinfo.tm_year += 1;
	isLeapYearRaw(timeinfo.tm_year + 1900);
}

void leap_year_check_call_on_conversion2(tm timeinfo){
	timeinfo.tm_year += 1;
	WORD year = get_civil_year(timeinfo);
	isLeapYearRaw(year);
}

WORD getDaysInMonth(WORD year, WORD month){
	// simplified
	if(month == 2){
		return isLeapYearRaw(year) ? 29 : 28;
	}
	// else assume logic for every other month,
	// returning 30 for simplicity
	return 30;
}

WORD get_civil_year_raw(WORD year){
	return year + 1900;
}

void leap_year_check_call_on_conversion3(tm timeinfo, WORD year, WORD month, WORD delta){
	year += delta;
	WORD days = getDaysInMonth(get_civil_year_raw(year), month);
	timeinfo.tm_year = year;
}

void assumed_maketime_conversion1(tm timeinfo)
{
	//the docs of mktime suggest feb29 is handled, and conversion will occur automatically
	//no check required.
	timeinfo.tm_year += 1;

	mktime(&timeinfo);
}


void bad_leap_year_check_logic1(tm timeinfo){
	timeinfo.tm_year += 1; // $ Alert[cpp/leap-year/unchecked-after-arithmetic-year-modification]

	WORD year = get_civil_year(timeinfo);

	// expected logic:
	//(year % 4) && ((year % 100) || !(year % 400 )))
 	WORD days = (!(year % 4) && (!(year % 100) || (year % 400))) ? 366 : 365;
}
