Added VarDateFromStr API.

This commit is contained in:
Jean-Claude Cote 1998-12-24 16:59:17 +00:00 committed by Alexandre Julliard
parent 506115b8c5
commit 9c7c8a4a36
4 changed files with 2119 additions and 114 deletions

View file

@ -16,6 +16,7 @@ C_SRCS = \
oledlg.c \
oleobj.c \
olesvr.c \
parsedt.c \
storage.c \
typelib.c \
variant.c

1333
ole/parsedt.c Normal file

File diff suppressed because it is too large Load diff

374
ole/parsedt.h Normal file
View file

@ -0,0 +1,374 @@
/*
PostgreSQL Data Base Management System (formerly known as Postgres, then
as Postgres95).
Copyright (c) 1994-7 Regents of the University of California
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose, without fee, and without a written agreement
is hereby granted, provided that the above copyright notice and this
paragraph and the following two paragraphs appear in all copies.
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
/*-------------------------------------------------------------------------
*
* dt.h--
* Definitions for the date/time and other date/time support code.
* The support code is shared with other date data types,
* including abstime, reltime, date, and time.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id$
*
*-------------------------------------------------------------------------
*/
#ifndef DT_H
#define DT_H
#include <time.h>
#include <math.h>
/* We have to include stdlib.h here because it defines many of these macros
on some platforms, and we only want our definitions used if stdlib.h doesn't
have its own.
*/
#include <stdlib.h>
/* ----------------------------------------------------------------
* Section 1: bool, true, false, TRUE, FALSE
* ----------------------------------------------------------------
*/
/*
* bool --
* Boolean value, either true or false.
*
*/
#define false ((char) 0)
#define true ((char) 1)
#ifndef __cplusplus
#ifndef bool
typedef char bool;
#endif /* ndef bool */
#endif /* not C++ */
typedef bool *BoolPtr;
#ifndef TRUE
#define TRUE 1
#endif /* TRUE */
#ifndef FALSE
#define FALSE 0
#endif /* FALSE */
/* ----------------------------------------------------------------
* Section 3: standard system types
* ----------------------------------------------------------------
*/
/*
* intN --
* Signed integer, EXACTLY N BITS IN SIZE,
* used for numerical computations and the
* frontend/backend protocol.
*/
typedef signed char int8; /* == 8 bits */
typedef signed short int16; /* == 16 bits */
typedef signed int int32; /* == 32 bits */
/*
* uintN --
* Unsigned integer, EXACTLY N BITS IN SIZE,
* used for numerical computations and the
* frontend/backend protocol.
*/
typedef unsigned char uint8; /* == 8 bits */
typedef unsigned short uint16; /* == 16 bits */
typedef unsigned int uint32; /* == 32 bits */
/*
* floatN --
* Floating point number, AT LEAST N BITS IN SIZE,
* used for numerical computations.
*
* Since sizeof(floatN) may be > sizeof(char *), always pass
* floatN by reference.
*/
typedef float float32data;
typedef double float64data;
typedef float *float32;
typedef double *float64;
/*
* boolN --
* Boolean value, AT LEAST N BITS IN SIZE.
*/
typedef uint8 bool8; /* >= 8 bits */
typedef uint16 bool16; /* >= 16 bits */
typedef uint32 bool32; /* >= 32 bits */
/* Date/Time Configuration
*
* Constants to pass info from runtime environment:
* USE_POSTGRES_DATES specifies traditional postgres format for output.
* USE_ISO_DATES specifies ISO-compliant format for output.
* USE_SQL_DATES specified Oracle/Ingres-compliant format for output.
* USE_GERMAN_DATES specifies German-style dd.mm/yyyy date format.
*
* DateStyle specifies preference for date formatting for output.
* EuroDates if client prefers dates interpreted and written w/European conventions.
*
* HasCTZSet if client timezone is specified by client.
* CDayLight is the apparent daylight savings time status.
* CTimeZone is the timezone offset in seconds.
* CTZName is the timezone label.
*/
#define USE_POSTGRES_DATES 0
#define USE_ISO_DATES 1
#define USE_SQL_DATES 2
#define USE_GERMAN_DATES 3
int DateStyle;
bool EuroDates;
int CTimeZone;
typedef double float8;
struct varlena
{
int vl_len;
char vl_dat[1];
};
typedef struct varlena text;
typedef int AbsoluteTime;
typedef int RelativeTime;
/*
* Note a leap year is one that is a multiple of 4
* but not of a 100. Except if it is a multiple of
* 400 then it is a leap year.
*/
#define isleap(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
/*
* DateTime represents absolute time.
* TimeSpan represents delta time. Keep track of months (and years)
* separately since the elapsed time spanned is unknown until instantiated
* relative to an absolute time.
*
* Note that Postgres uses "time interval" to mean a bounded interval,
* consisting of a beginning and ending time, not a time span - thomas 97/03/20
*/
typedef double DateTime;
typedef struct
{
double time; /* all time units other than months and
* years */
int month; /* months and years, after time for
* alignment */
} TimeSpan;
/* ----------------------------------------------------------------
* time types + support macros
*
* String definitions for standard time quantities.
*
* These strings are the defaults used to form output time strings.
* Other alternate forms are hardcoded into token tables in dt.c.
* ----------------------------------------------------------------
*/
#define DAGO "ago"
#define DCURRENT "current"
#define EPOCH "epoch"
#define INVALID "invalid"
#define EARLY "-infinity"
#define LATE "infinity"
#define NOW "now"
#define TODAY "today"
#define TOMORROW "tomorrow"
#define YESTERDAY "yesterday"
#define ZULU "zulu"
#define DMICROSEC "usecond"
#define DMILLISEC "msecond"
#define DSECOND "second"
#define DMINUTE "minute"
#define DHOUR "hour"
#define DDAY "day"
#define DWEEK "week"
#define DMONTH "month"
#define DQUARTER "quarter"
#define DYEAR "year"
#define DDECADE "decade"
#define DCENTURY "century"
#define DMILLENIUM "millenium"
#define DA_D "ad"
#define DB_C "bc"
#define DTIMEZONE "timezone"
/*
* Fundamental time field definitions for parsing.
*
* Meridian: am, pm, or 24-hour style.
* Millenium: ad, bc
*/
#define AM 0
#define PM 1
#define HR24 2
#define AD 0
#define BC 1
/*
* Fields for time decoding.
* Can't have more of these than there are bits in an unsigned int
* since these are turned into bit masks during parsing and decoding.
*/
#define RESERV 0
#define MONTH 1
#define YEAR 2
#define DAY 3
#define TIMES 4 /* not used - thomas 1997-07-14 */
#define TZ 5
#define DTZ 6
#define DTZMOD 7
#define IGNOREFIELD 8
#define AMPM 9
#define HOUR 10
#define MINUTE 11
#define SECOND 12
#define DOY 13
#define DOW 14
#define UNITS 15
#define ADBC 16
/* these are only for relative dates */
#define AGO 17
#define ABS_BEFORE 18
#define ABS_AFTER 19
/*
* Token field definitions for time parsing and decoding.
* These need to fit into the datetkn table type.
* At the moment, that means keep them within [-127,127].
* These are also used for bit masks in DecodeDateDelta()
* so actually restrict them to within [0,31] for now.
* - thomas 97/06/19
* Not all of these fields are used for masks in DecodeDateDelta
* so allow some larger than 31. - thomas 1997-11-17
*/
#define DTK_NUMBER 0
#define DTK_STRING 1
#define DTK_DATE 2
#define DTK_TIME 3
#define DTK_TZ 4
#define DTK_AGO 5
#define DTK_SPECIAL 6
#define DTK_INVALID 7
#define DTK_CURRENT 8
#define DTK_EARLY 9
#define DTK_LATE 10
#define DTK_EPOCH 11
#define DTK_NOW 12
#define DTK_YESTERDAY 13
#define DTK_TODAY 14
#define DTK_TOMORROW 15
#define DTK_ZULU 16
#define DTK_DELTA 17
#define DTK_SECOND 18
#define DTK_MINUTE 19
#define DTK_HOUR 20
#define DTK_DAY 21
#define DTK_WEEK 22
#define DTK_MONTH 23
#define DTK_QUARTER 24
#define DTK_YEAR 25
#define DTK_DECADE 26
#define DTK_CENTURY 27
#define DTK_MILLENIUM 28
#define DTK_MILLISEC 29
#define DTK_MICROSEC 30
#define DTK_DOW 32
#define DTK_DOY 33
#define DTK_TZ_HOUR 34
#define DTK_TZ_MINUTE 35
/*
* Bit mask definitions for time parsing.
*/
#define DTK_M(t) (0x01 << (t))
#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND))
#define MAXDATELEN 47 /* maximum possible length of an input
* date string */
#define MAXDATEFIELDS 25 /* maximum possible number of fields in a
* date string */
#define TOKMAXLEN 10 /* only this many chars are stored in
* datetktbl */
/* keep this struct small; it gets used a lot */
typedef struct
{
#if defined(_AIX)
char *token;
#else
char token[TOKMAXLEN];
#endif /* _AIX */
char type;
char value; /* this may be unsigned, alas */
} datetkn;
/*
* dt.c prototypes
*/
void j2date(int jd, int *year, int *month, int *day);
int date2j(int year, int month, int day);
int ParseDateTime(char *timestr, char *lowstr,
char **field, int *ftype, int maxfields, int *numfields);
int DecodeDateTime(char **field, int *ftype,
int nf, int *dtype, struct tm * tm, double *fsec, int *tzp);
int DecodeTimeOnly(char **field, int *ftype, int nf,
int *dtype, struct tm * tm, double *fsec);
#endif /* DT_H */

View file

@ -15,8 +15,9 @@
* - The Variant APIs do not the following types: IUknown, IDispatch, DECIMAL and SafeArray.
* The prototypes for these are commented out in the oleauto.h file. They need
* to be implemented and cases need to be added to the switches of the existing APIs.
* - The parsing of date for the VarDateFromStr still needs to be done. I'm currently
* working on this.
* - The parsing of date for the VarDateFromStr is not complete.
* - The date manipulations do not support date prior to 1900.
* - The parsing does not accept has many formats has the Windows implementation.
*/
#include "wintypes.h"
@ -25,6 +26,7 @@
#include "debug.h"
#include "winerror.h"
#include "mapidefs.h"
#include "parsedt.h"
#include <string.h>
#include <stdlib.h>
@ -72,6 +74,391 @@ static const DATE DATE_MAX = 2958465;
#define BUFFER_MAX 1024
static char pBuffer[BUFFER_MAX];
/*
* Note a leap year is one that is a multiple of 4
* but not of a 100. Except if it is a multiple of
* 400 then it is a leap year.
*/
/* According to postgeSQL date parsing functions there is
* a leap year when this expression is true.
* (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
* So according to this there is 365.2515 days in one year.
* One + every four years: 1/4 -> 365.25
* One - every 100 years: 1/100 -> 365.001
* One + every 400 years: 1/400 -> 365.0025
*/
static const double DAYS_IN_ONE_YEAR = 365.2515;
/******************************************************************************
* DateTimeStringToTm [INTERNAL]
*
* Converts a string representation of a date and/or time to a tm structure.
*
* Note this function uses the postgresql date parsing functions found
* in the parsedt.c file.
*
* Returns TRUE if successfull.
*
* Note: This function does not parse the day of the week,
* daylight savings time. It will only fill the followin fields in
* the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
*
******************************************************************************/
static BOOL32 DateTimeStringToTm( OLECHAR32* strIn, LCID lcid, struct tm* pTm )
{
BOOL32 res = FALSE;
double fsec;
int tzp;
int dtype;
int nf;
char *field[MAXDATEFIELDS];
int ftype[MAXDATEFIELDS];
char lowstr[MAXDATELEN + 1];
char* strDateTime = NULL;
/* Convert the string to ASCII since this is the only format
* postgesql can handle.
*/
strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
if( strDateTime != NULL )
{
/* Make sure we don't go over the maximum length
* accepted by postgesql.
*/
if( strlen( strDateTime ) <= MAXDATELEN )
{
if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
{
if( lcid & VAR_DATEVALUEONLY )
{
/* Get the date information.
* It returns 0 if date information was
* present and 1 if only time information was present.
* -1 if an error occures.
*/
if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
{
/* Eliminate the time information since we
* were asked to get date information only.
*/
pTm->tm_sec = 0;
pTm->tm_min = 0;
pTm->tm_hour = 0;
res = TRUE;
}
}
if( lcid & VAR_TIMEVALUEONLY )
{
/* Get time information only.
*/
if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
{
res = TRUE;
}
}
else
{
/* Get both date and time information.
* It returns 0 if date information was
* present and 1 if only time information was present.
* -1 if an error occures.
*/
if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
{
res = TRUE;
}
}
}
}
HeapFree( GetProcessHeap(), 0, strDateTime );
}
return res;
}
/******************************************************************************
* TmToDATE [INTERNAL]
*
* The date is implemented using an 8 byte floating-point number.
* Days are represented by whole numbers increments starting with 0.00 has
* being December 30 1899, midnight.
* The hours are expressed as the fractional part of the number.
* December 30 1899 at midnight = 0.00
* January 1 1900 at midnight = 2.00
* January 4 1900 at 6 AM = 5.25
* January 4 1900 at noon = 5.50
* December 29 1899 at midnight = -1.00
* December 18 1899 at midnight = -12.00
* December 18 1899 at 6AM = -12.25
* December 18 1899 at 6PM = -12.75
* December 19 1899 at midnight = -11.00
* The tm structure is as follows:
* struct tm {
* int tm_sec; seconds after the minute - [0,59]
* 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
* int tm_wday; days since Sunday - [0,6]
* int tm_yday; days since January 1 - [0,365]
* int tm_isdst; daylight savings time flag
* };
*
* Note: This function does not use the tm_wday, tm_yday, tm_wday,
* and tm_isdst fields of the tm structure. And only converts years
* after 1900.
*
* Returns TRUE if successfull.
*/
static BOOL32 TmToDATE( struct tm* pTm, DATE *pDateOut )
{
if( (pTm->tm_year - 1900) >= 0 )
{
int leapYear = 0;
/* Start at 1. This is the way DATE is defined.
* January 1, 1900 at Midnight is 1.00.
* January 1, 1900 at 6AM is 1.25.
* and so on.
*/
*pDateOut = 1;
/* Add the number of days corresponding to
* tm_year.
*/
*pDateOut += (pTm->tm_year - 1900) * 365;
/* Add the leap days in the previous years between now and 1900.
* Note a leap year is one that is a multiple of 4
* but not of a 100. Except if it is a multiple of
* 400 then it is a leap year.
*/
*pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
*pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
*pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
/* Set the leap year flag if the
* current year specified by tm_year is a
* leap year. This will be used to add a day
* to the day count.
*/
if( isleap( pTm->tm_year ) )
leapYear = 1;
/* Add the number of days corresponding to
* the month.
*/
switch( pTm->tm_mon )
{
case 2:
*pDateOut += 31;
break;
case 3:
*pDateOut += ( 59 + leapYear );
break;
case 4:
*pDateOut += ( 90 + leapYear );
break;
case 5:
*pDateOut += ( 120 + leapYear );
break;
case 6:
*pDateOut += ( 151 + leapYear );
break;
case 7:
*pDateOut += ( 181 + leapYear );
break;
case 8:
*pDateOut += ( 212 + leapYear );
break;
case 9:
*pDateOut += ( 243 + leapYear );
break;
case 10:
*pDateOut += ( 273 + leapYear );
break;
case 11:
*pDateOut += ( 304 + leapYear );
break;
case 12:
*pDateOut += ( 334 + leapYear );
break;
}
/* Add the number of days in this month.
*/
*pDateOut += pTm->tm_mday;
/* Add the number of seconds, minutes, and hours
* to the DATE. Note these are the fracionnal part
* of the DATE so seconds / number of seconds in a day.
*/
*pDateOut += pTm->tm_hour / 24.0;
*pDateOut += pTm->tm_min / 1440.0;
*pDateOut += pTm->tm_sec / 86400.0;
return TRUE;
}
return FALSE;
}
/******************************************************************************
* DateToTm [INTERNAL]
*
* This function converst a windows DATE to a tm structure.
*
* It does not fill all the fields of the tm structure.
* Here is a list of the fields that are filled:
* tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
*
* Note this function does not support dates before the January 1, 1900
* or ( dateIn < 2.0 ).
*
* Returns TRUE if successfull.
*/
static BOOL32 DateToTm( DATE dateIn, LCID lcid, struct tm* pTm )
{
/* Do not process dates smaller than January 1, 1900.
* Which corresponds to 2.0 in the windows DATE format.
*/
if( dateIn >= 2.0 )
{
double decimalPart = 0.0;
double wholePart = 0.0;
pTm->tm_sec = 0;
pTm->tm_min = 0;
pTm->tm_hour = 0;
pTm->tm_mday = 0;
pTm->tm_mon = 0;
pTm->tm_year = 0;
pTm->tm_wday = 0;
pTm->tm_yday = 0;
pTm->tm_isdst = 0;
pTm->tm_gmtoff = 0;
pTm->tm_zone = 0;
/* Because of the nature of DATE format witch
* associates 2.0 to January 1, 1900. We will
* remove 1.0 from the whole part of the DATE
* so that in the following code 1.0
* will correspond to January 1, 1900.
* This simplyfies the processing of the DATE value.
*/
dateIn -= 1.0;
wholePart = (double) floor( dateIn );
decimalPart = fmod( dateIn, wholePart );
if( !(lcid & VAR_TIMEVALUEONLY) )
{
int nDay = 0;
int leapYear = 0;
double yearsSince1900 = 0;
/* Start at 1900, this where the DATE time 0.0 starts.
*/
pTm->tm_year = 1900;
/* find in what year the day in the "wholePart" falls into.
* add the value to the year field.
*/
yearsSince1900 = floor( wholePart / DAYS_IN_ONE_YEAR );
pTm->tm_year += yearsSince1900;
/* determine if this is a leap year.
*/
if( isleap( pTm->tm_year ) )
leapYear = 1;
/* find what day of that year does the "wholePart" corresponds to.
* Note: nDay is in [1-366] format
*/
nDay = (int) ( wholePart - floor( yearsSince1900 * DAYS_IN_ONE_YEAR ) );
/* Set the tm_yday value.
* Note: The day is must be converted from [1-366] to [0-365]
*/
//pTm->tm_yday = nDay - 1;
/* find which mount this day corresponds to.
*/
if( nDay <= 31 )
{
pTm->tm_mday = nDay;
pTm->tm_mon = 0;
}
else if( nDay <= ( 59 + leapYear ) )
{
pTm->tm_mday = nDay - 31;
pTm->tm_mon = 1;
}
else if( nDay <= ( 90 + leapYear ) )
{
pTm->tm_mday = nDay - ( 59 + leapYear );
pTm->tm_mon = 2;
}
else if( nDay <= ( 120 + leapYear ) )
{
pTm->tm_mday = nDay - ( 90 + leapYear );
pTm->tm_mon = 3;
}
else if( nDay <= ( 151 + leapYear ) )
{
pTm->tm_mday = nDay - ( 120 + leapYear );
pTm->tm_mon = 4;
}
else if( nDay <= ( 181 + leapYear ) )
{
pTm->tm_mday = nDay - ( 151 + leapYear );
pTm->tm_mon = 5;
}
else if( nDay <= ( 212 + leapYear ) )
{
pTm->tm_mday = nDay - ( 181 + leapYear );
pTm->tm_mon = 6;
}
else if( nDay <= ( 243 + leapYear ) )
{
pTm->tm_mday = nDay - ( 212 + leapYear );
pTm->tm_mon = 7;
}
else if( nDay <= ( 273 + leapYear ) )
{
pTm->tm_mday = nDay - ( 243 + leapYear );
pTm->tm_mon = 8;
}
else if( nDay <= ( 304 + leapYear ) )
{
pTm->tm_mday = nDay - ( 273 + leapYear );
pTm->tm_mon = 9;
}
else if( nDay <= ( 334 + leapYear ) )
{
pTm->tm_mday = nDay - ( 304 + leapYear );
pTm->tm_mon = 10;
}
else if( nDay <= ( 365 + leapYear ) )
{
pTm->tm_mday = nDay - ( 334 + leapYear );
pTm->tm_mon = 11;
}
}
if( !(lcid & VAR_DATEVALUEONLY) )
{
/* find the number of seconds in this day.
* fractional part times, hours, minutes, seconds.
*/
pTm->tm_hour = (int) ( decimalPart * 24 );
pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
pTm->tm_sec = (int) ( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 );
}
return TRUE;
}
return FALSE;
}
/******************************************************************************
@ -2555,12 +2942,9 @@ HRESULT WINAPI VarDateFromI432(LONG lIn, DATE* pdateOut)
*/
HRESULT WINAPI VarDateFromR432(FLOAT fltIn, DATE* pdateOut)
{
unsigned long test = 0;
TRACE( ole, "( %f, %p ), stub\n", fltIn, pdateOut );
test = (unsigned long) fltIn;
if( test < DATE_MIN || test > DATE_MAX )
if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
{
return DISP_E_OVERFLOW;
}
@ -2575,12 +2959,9 @@ HRESULT WINAPI VarDateFromR432(FLOAT fltIn, DATE* pdateOut)
*/
HRESULT WINAPI VarDateFromR832(double dblIn, DATE* pdateOut)
{
unsigned long test = 0;
TRACE( ole, "( %f, %p ), stub\n", dblIn, pdateOut );
test = (unsigned long) dblIn;
if( test < DATE_MIN || test > DATE_MAX )
if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
{
return DISP_E_OVERFLOW;
}
@ -2618,8 +2999,22 @@ HRESULT WINAPI VarDateFromR832(double dblIn, DATE* pdateOut)
HRESULT WINAPI VarDateFromStr32(OLECHAR32* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
{
HRESULT ret = S_OK;
struct tm TM = { 0,0,0,0,0,0,0,0,0 };
TRACE( ole, "( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
if( DateTimeStringToTm( strIn, lcid, &TM ) )
{
if( TmToDATE( &TM, pdateOut ) == FALSE )
{
ret = E_INVALIDARG;
}
}
else
{
ret = DISP_E_TYPEMISMATCH;
}
FIXME( ole, "( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
return ret;
}
@ -2780,7 +3175,7 @@ HRESULT WINAPI VarBstrFromR832(double dblIn, LCID lcid, ULONG dwFlags, BSTR32* p
* 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_year; years
* int tm_wday; days since Sunday - [0,6]
* int tm_yday; days since January 1 - [0,365]
* int tm_isdst; daylight savings time flag
@ -2788,105 +3183,13 @@ HRESULT WINAPI VarBstrFromR832(double dblIn, LCID lcid, ULONG dwFlags, BSTR32* p
*/
HRESULT WINAPI VarBstrFromDate32(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR32* pbstrOut)
{
/* If the date is not after the 1900 return an error because
* the tm structure does not allow such dates.
*/
if( dateIn >= 1.0 )
{
double decimalPart = 0.0;
double wholePart = 0.0;
struct tm TM = {0,0,0,0,0,0,0,0,0};
wholePart = (double) (long) dateIn;
decimalPart = fmod( dateIn, wholePart );
TRACE( ole, "( %f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
if( !(lcid & VAR_TIMEVALUEONLY) )
{
int nDay = 0;
int leapYear = 0;
/* find in what year the day in the "wholePart" falls into.
*/
TM.tm_year = (int) ( wholePart / 365.25 );
/* determine if this is a leap year.
*/
if( ( TM.tm_year % 4 ) == 0 )
leapYear = 1;
/* find what day of that year does the "wholePart" corresponds to.
* the day is [1-366]
*/
nDay = (int) ( wholePart - ( TM.tm_year * 365.25 ) );
TM.tm_yday = nDay - 1;
/* find which mount this day corresponds to.
*/
if( nDay <= 31 )
if( DateToTm( dateIn, lcid, &TM ) == FALSE )
{
TM.tm_mday = nDay;
TM.tm_mon = 0;
}
else if( nDay <= ( 59 + leapYear ) )
{
TM.tm_mday = nDay - 31;
TM.tm_mon = 1;
}
else if( nDay <= ( 90 + leapYear ) )
{
TM.tm_mday = nDay - ( 59 + leapYear );
TM.tm_mon = 2;
}
else if( nDay <= ( 120 + leapYear ) )
{
TM.tm_mday = nDay - ( 90 + leapYear );
TM.tm_mon = 3;
}
else if( nDay <= ( 151 + leapYear ) )
{
TM.tm_mday = nDay - ( 120 + leapYear );
TM.tm_mon = 4;
}
else if( nDay <= ( 181 + leapYear ) )
{
TM.tm_mday = nDay - ( 151 + leapYear );
TM.tm_mon = 5;
}
else if( nDay <= ( 212 + leapYear ) )
{
TM.tm_mday = nDay - ( 181 + leapYear );
TM.tm_mon = 6;
}
else if( nDay <= ( 243 + leapYear ) )
{
TM.tm_mday = nDay - ( 212 + leapYear );
TM.tm_mon = 7;
}
else if( nDay <= ( 273 + leapYear ) )
{
TM.tm_mday = nDay - ( 243 + leapYear );
TM.tm_mon = 8;
}
else if( nDay <= ( 304 + leapYear ) )
{
TM.tm_mday = nDay - ( 273 + leapYear );
TM.tm_mon = 9;
}
else if( nDay <= ( 334 + leapYear ) )
{
TM.tm_mday = nDay - ( 304 + leapYear );
TM.tm_mon = 10;
}
else if( nDay <= ( 365 + leapYear ) )
{
TM.tm_mday = nDay - ( 334 + leapYear );
TM.tm_mon = 11;
}
}
if( !(lcid & VAR_DATEVALUEONLY) )
{
/* find the number of seconds in this day.
* fractional part times, hours, minutes, seconds.
*/
TM.tm_hour = (int) ( decimalPart * 24 );
TM.tm_min = (int) ( ( ( decimalPart * 24 ) - TM.tm_hour ) * 60 );
TM.tm_sec = (int) ( ( ( decimalPart * 24 * 60 ) - ( TM.tm_hour * 60 ) - TM.tm_min ) * 60 );
return E_INVALIDARG;
}
if( lcid & VAR_DATEVALUEONLY )
@ -2894,15 +3197,9 @@ HRESULT WINAPI VarBstrFromDate32(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR32*
else if( lcid & VAR_TIMEVALUEONLY )
strftime( pBuffer, BUFFER_MAX, "%X", &TM );
else
strftime( pBuffer, 100, "%x %X", &TM );
strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
*pbstrOut = StringDupAtoBstr( pBuffer );
}
else
{
FIXME( ole, "( %f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
return E_INVALIDARG;
}
return S_OK;
}