Logo Search packages:      
Sourcecode: falconpl version File versions  Download package

time_ext.cpp

Go to the documentation of this file.
/*
   FALCON - The Falcon Programming Language.
   FILE: time_ext.cpp

   Date and time support for RTL
   -------------------------------------------------------------------
   Author: Giancarlo Niccolai
   Begin: ven nov 12 2004

   -------------------------------------------------------------------
   (C) Copyright 2004: the FALCON developers (see list in AUTHORS file)

   See LICENSE file for licensing details.
*/

/** \file
   Date and time support for RTL.
*/

#include <falcon/module.h>
#include <falcon/vm.h>
#include <falcon/sys.h>
#include <falcon/symbol.h>
#include <math.h>
#include <falcon/cobject.h>
#include <falcon/fassert.h>

#include <falcon/timestamp.h>
#include <falcon/time_sys.h>

/*#
   @beginmodule falcon_rtl
*/

namespace Falcon { namespace Ext {

bool TimeStamp_copy( const CoreObject *origin, CoreObject *dateObj )
{
   Item data;
   origin->getProperty( "year", data );
   dateObj->setProperty( "year", data );
   origin->getProperty( "month", data );
   dateObj->setProperty( "month", data );
   origin->getProperty( "day", data );
   dateObj->setProperty( "day", data );
   origin->getProperty( "hour", data );
   dateObj->setProperty( "hour", data );
   origin->getProperty( "minute", data );
   dateObj->setProperty( "minute", data );
   origin->getProperty( "second", data );
   dateObj->setProperty( "second", data );
   origin->getProperty( "msec", data );
   dateObj->setProperty( "msec", data );
   origin->getProperty( "timezone", data );
   dateObj->setProperty( "timezone", data );
   return true;
}

/*#
   @class TimeStamp
   @brief Representation of times in the system.
   @param date Other TimeStamp instance from which to copy the new instance.

   The TimeStamp class can be used to retrieve the system time and date.
   It is also used by other entities in the RTL to return informations
   about the date (i.e. the @a FileReadStats ).

   @prop year Timestamp year, absolute value.
   @prop month Month of the year, starting from 1.
   @prop day Day of month, starting from 1.
   @prop hour Hour in range 0 - 23.
   @prop minute Minute in range 0 - 59.
   @prop second Second in range 0 - 59.
   @prop msec Millisecond in range 0 - 999.
   @prop timezone A timezone code (see @a TimeZone class).
*/

/*#
   @init TimeStamp

   The instance is created empty and unset, unless the @b date parameter
   is provided. In that case, the new instance is copied from a previously
   created one.

   The provided parameter may also be a "long opaque format" generated by
   the @a TimeStamp.toLongFormat method.

   To update the instance with the current system time, use @a TimeStamp.currentTime
*/
FALCON_FUNC  TimeStamp_init ( ::Falcon::VMachine *vm )
{
   Item *date = vm->param(0);
   CoreObject *self = vm->self().asObject();

   if ( date != 0 ) {
      if ( date->isInteger() ) {
         self->setUserData( new TimeStamp( date->asInteger() ) );
      }
      else if ( date->isObject() ) {
         CoreObject *other = date->asObject();
         if( !other->derivedFrom( "TimeStamp" ) ) {
            vm->raiseModError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).
               extra( "Parameter is not a TimeStamp" ) ) );
         }
         self->setUserData( new TimeStamp );

         TimeStamp_copy( other, self );
      }
      else {
         vm->raiseModError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).
               extra( "TimeStamp class init requires an integer or TimeStamp parameter" ) ) );
      }
   }
   else
      self->setUserData( new TimeStamp );
}

/*#
   @method currentTime TimeStamp
   @brief Fills this item with current time.

   Fills the value of the date with the current local time on the system.
   Timezone management is still not implemented.
*/

FALCON_FUNC  TimeStamp_currentTime ( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   TimeStamp *ts = (TimeStamp *) self->getUserData();
   Falcon::Sys::Time::currentTime( *ts );
}

/*#
   @method toString TimeStamp
   @brief Converts the current timestamp to a string.
   @optparam format Date formatting pattern in @b strftime format.
   @return The formatted timestamp.

   Returns a string representation of the time stamp. The returned format is
   YYYY-MM-DD HH:MM:SS.mmm. This function is just meant as a basic way to represent
   timestamps on output.

   @note In version 0.8.x, The extra format parameter is internally
   passed to strftime() C standard function. Some compiler/C libraries
   may abort the program if the given format string is malformed.
   An internal re-implementation of the method will be available
   in the next versions; it will be granted to be compatible with strftime()
   and will offer falcon-specific formattings.

   @note Some specific extra formats available in 0.8.x:
   %q (milliseconds), %Q (zero-padded milliseconds) and
      %i (Internet format, RFC-2822).
*/
FALCON_FUNC  TimeStamp_toString ( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   TimeStamp *ts = (TimeStamp *) self->getUserData();
   Item *format = vm->param( 0 );

   String *str = new GarbageString( vm );
   if( format != 0 )
   {
      if( ! format->isString() )
      {
         vm->raiseModError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).
            extra( "[S]" ) ) );
         return;
      }

      if( !  ts->toString( *str, *format->asString() ) )
      {
         vm->raiseModError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).
            extra( "Invalid TimeStamp format" ) ) );
         return;
      }
   }
   else {
      ts->toString( *str );
   }
   vm->retval( str );
}

static void internal_add_dist( ::Falcon::VMachine *vm, int mode )
{
   CoreObject *self = vm->self().asObject();
   TimeStamp *ts1, *ts2;
   ts1 = (TimeStamp *) self->getUserData();
   Item *date = vm->param( 0 );

   if ( date->isObject() )
   {
      CoreObject *other = date->asObject();
      if( !other->derivedFrom( "TimeStamp" ) )
      {
         vm->raiseModError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).
               extra( "not a TimeStamp" ) ) );
         return;
      }


      ts2 = (TimeStamp *) date->asObject()->getUserData();
      if ( mode == 0 )
         ts1->add( *ts2 );
      else
         ts1->distance( *ts2 );

      vm->retnil();
   }
   else {
      vm->raiseModError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).
            extra( "Not a TimeStamp" ) ) );
   }
}

/*#
   @method add TimeStamp
   @brief Converts the current timestamp to a string.
   @param timestamp A timestamp to add

   Alters this timestamp by adding another one to itself.
   Years, months, days, hours, minutes, seconds and milliseconds
   from the parameters are added, and the target date is re-validated.
*/
FALCON_FUNC  TimeStamp_add ( ::Falcon::VMachine *vm )
{
   internal_add_dist( vm, 0 );
}

/*#
   @method distance TimeStamp
   @brief Converts the current timestamp to a string.
   @param timestamp The timestamp from which to calculate the distance.

   The parameter is subtracted from the current object; the number of days,
   hours, minutes, seconds and milliseconds between the two dates is stored
   in the current object. The values may be negative if the given timestamp
   parameter is greater than this object.
*/
FALCON_FUNC  TimeStamp_distance ( ::Falcon::VMachine *vm )
{
   internal_add_dist( vm, 1 );
}

/*#
   @method isValid TimeStamp
   @brief Checks the validity of this TimeStamp.
   @return True if this timestamp represents a valid moment in time.

   Returns true if the data in the timestamp represents a valid date.
   The function takes into consideration leap years.
*/
FALCON_FUNC  TimeStamp_isValid ( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   TimeStamp *ts = (TimeStamp *) self->getUserData();
   vm->retval( ts->isValid() );
}

/*#
   @method isLeapYear TimeStamp
   @brief Checks if the year in this TimeStamp is a LeapYear.
   @return True if this timestamp is in a leap year, false otherwise.

   Returns true if year member of this timestamp is leap, false otherwise.
   Calculation is reliable only for years past 1700.
*/
FALCON_FUNC  TimeStamp_isLeapYear ( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   TimeStamp *ts = (TimeStamp *) self->getUserData();
   vm->retval( ts->isLeapYear() );
}

/*#
   @method dayOfWeek TimeStamp
   @brief Returns the weekday in which this TimeStamp falls.
   @return A number representing a day in the week.

   Returns the day of week calculated on this object. The returned number is in
   range 0 to 6 included, 0 being Sunday and 6 being Saturday. The function is
   reliable only for dates past January the first 1700.
*/
FALCON_FUNC  TimeStamp_dayOfWeek ( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   TimeStamp *ts = (TimeStamp *) self->getUserData();
   vm->retval( ts->dayOfWeek() );
}

/*#
   @method dayOfYear TimeStamp
   @brief Returns the days passed since the beginning of the year in this TimeStamp
   @return A number of days in the year.

   Returns the day in the year represented by the current object. The returned
   number will range between 1 for January the first and 365 or 366 (if the current year is
   leap) for December the 31th.
*/
FALCON_FUNC  TimeStamp_dayOfYear ( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   TimeStamp *ts = (TimeStamp *) self->getUserData();
   vm->retval( ts->dayOfYear() );
}

/*#
   @method toLongFormat TimeStamp
   @brief Returns a compressed date representation.
   @return A date in an opaque "long format".

   Returns a Falcon integer which contains packed binary data representing
   this object. The returned data is opaque and should not be used to
   compare different dates.
*/
FALCON_FUNC  TimeStamp_toLongFormat ( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   TimeStamp *ts = (TimeStamp *) self->getUserData();
   vm->retval( ts->toLongFormat() );
}

/*#
   @method fromLongFormat TimeStamp
   @brief Sets this date using a compressed opaque "long format" data.

   Fills the data in this object using a binary packed data which can be
   stored in a Falcon integer value (64 bits). A valid value can be only
   obtained with the toLongFormat() method. This two methods are just
   meant for easier serialization; timestamps in long format cannot be
   compared or summed.
*/
FALCON_FUNC  TimeStamp_fromLongFormat ( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   TimeStamp *ts = (TimeStamp *) self->getUserData();

   Item *data = vm->param( 0 );

   if ( ! data->isInteger() )
   {
      vm->raiseModError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).
         extra( "Only integer parameter allowed" ) ) );
   }

   ts->fromLongFormat( data->asInteger() );
}

/*#
   @method compare TimeStamp
   @brief Compare another TimeStamp against this one.
   @param timestamp The TimeStamp to be compared.
   @return -1, 0 or 1.

   The given timestamp is compared to this object. If this object is greater than
   the target timestamp, 1 is returned; if it's smaller (before), -1 is returned.
   If the two timestamp are exactly the same, 0 is returned.
*/
FALCON_FUNC  TimeStamp_compare ( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   TimeStamp *ts1, *ts2;
   ts1 = (TimeStamp *) self->getUserData();
   Item *date = vm->param( 0 );

   if ( date->isObject() )
   {
      CoreObject *other = date->asObject();
      if( other->derivedFrom( "TimeStamp" ) )
      {
         ts2 = (TimeStamp *) date->asObject()->getUserData();
         vm->retval( ts1->compare( *ts2 ) );
      }
      else {
         vm->retval( vm->self().compare( *date ) );
      }
   }
   else {
      vm->retval( vm->self().compare( *date ) );
   }
}

/*#
   @method fromRFC2822 TimeStamp
   @brief Sets this date from a RFC 2822 string.
   @param sTimestamp A string containing a date in RFC 2822 format.
   @return True on success, false on failure.

   RFC 2822 format is the textual descriptive format used in Internet
   transactions. It's composed with:
   - Day of the week signature
   - Month signature
   - Day in the current month
   - 4 digits year
   - Time in HH:MM:SS format
   - Timezone name or displacement.

   A sample looks like:
   @code
      Thu, 01 May 2008 23:52:34 +0200
   @endcode

   If the given string is not a valid timestamp in the RFC 2822 format, the function
   will return false.

   @note Part of this timestamp may be corrupted after a faulty try; be sure to save
   this TimeStamp before trying the conversion, if it is needed.
*/
FALCON_FUNC  TimeStamp_fromRFC2822 ( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   Item *i_string = vm->param(0);
   if( i_string == 0 || ! i_string->isString() )
   {
      vm->raiseModError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).
         extra( "S" ) ) );
      return;
   }

   TimeStamp *ts1 = (TimeStamp *) self->getUserData();
   vm->regA().setBoolean( TimeStamp::fromRFC2822( *ts1, *i_string->asString() ) );
}


/*#
   @method toRFC2822 TimeStamp
   @brief Format this TimeStamp in RFC 2822 format.
   @return A string with this timestamp converted, or nil if this TimeStamp is not valid.

   @see TimeStamp.fromRFC2822
*/
FALCON_FUNC  TimeStamp_toRFC2822 ( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   TimeStamp *ts1 = (TimeStamp *) self->getUserData();
   if ( ts1->isValid() )
   {
      GarbageString *str = new GarbageString( vm, 32 );
      ts1->toRFC2822( *str );
      vm->retval( str );
   }
   else
      vm->retnil();
}

/*#
   @method changeZone TimeStamp
   @brief Change the time zone in this timestamp, maintaing the same absolute value.
   @param zone The new time zone.

   This methods shifts forward or backward this timestamp according with the relative
   shift between the @a TimeStamp.timezone member and the @b zone parameter. After the
   shift is performed, the new zone is set in the timezone property of this object.

   In example, to convert the local time in GMT:
   @code
      now = CurrentTime()
      > "Local time: ", now
      now.changeZone( TimeZone.GMT )
      > "GMT: ", now
   @endcode

   As assigning a new time zone to the @b timezone property is not subject to any control,
   it is possible to set an arbitrary time and timezone by normal assignment, and then
   convert it to another time zone using this method.

   In example:
   @code
      a_gmt_time = decodeTime( "..." )
      // let's say we know the timestamp is GMT.
      a_gmt_time.timezone = TimeZone.GMT

      // to convert in local time:
      localTime = a_gmt_time
      localTime.changeZone( TimeZone.local )
   @endcode

   The "local" zone is a special zone which is automatically converted in the system
   timezone; it can also be directly assigned to a timestamp, but it's preferable to
   determine the system timezone through @a TimeZone.getLocal.

   @see TimeZone
*/
FALCON_FUNC  TimeStamp_changeZone ( ::Falcon::VMachine *vm )
{
   Item *i_tz = vm->param(0);
   if( i_tz == 0 || ! i_tz->isOrdinal() )
   {
      vm->raiseModError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).
         extra( "N" ) ) );
      return;
   }
   int tz = (int) i_tz->forceInteger();
   if ( tz < 0 || tz >= 32 )
   {
      vm->raiseModError( new ParamError( ErrorParam( e_param_range, __LINE__ ).origin( e_orig_runtime ).
         extra( "Invalid timezone" ) ) );
      return;
   }
   CoreObject *self = vm->self().asObject();
   TimeStamp *ts1 = (TimeStamp *) self->getUserData();

   ts1->changeTimezone( (TimeZone) tz );
}

/*#
   @function CurrentTime
   @brief Returns the current system local time as a TimeStamp instance.
   @return A new TimeStamp instance.

   Returns the current system local time as a TimeStamp instance.
   The function can never fail.
*/

FALCON_FUNC  CurrentTime ( ::Falcon::VMachine *vm )
{
   // create the timestamp
   Item *ts_class = vm->findWKI( "TimeStamp" );
   //if we wrote the std module, can't be zero.
   fassert( ts_class != 0 );
   CoreObject *self = ts_class->asClass()->createInstance();
   TimeStamp *ts = new TimeStamp;

   Falcon::Sys::Time::currentTime( *ts );
   self->setUserData( ts );
   vm->retval( self );
}

/*#
   @function ParseRFC2822
   @brief Parses a RFC2822 formatted date and returns a timestamp instance.
   @return A valid @a TimeStamp instance or nil if the format is invalid.

   @see TimeStamp.fromRFC2822
*/
FALCON_FUNC  ParseRFC2822 ( ::Falcon::VMachine *vm )
{
   // verify that the string is valid
   Item *i_string = vm->param(0);
   if( i_string == 0 || ! i_string->isString() )
   {
      vm->raiseModError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).
         extra( "S" ) ) );
      return;
   }

   TimeStamp *ts1 = new TimeStamp;
   if( ! TimeStamp::fromRFC2822( *ts1, *i_string->asString() ) )
   {
      delete ts1;
      vm->retnil();
      return;
   }

   // create the timestamp
   Item *ts_class = vm->findWKI( "TimeStamp" );
   //if we wrote the std module, can't be zero.
   fassert( ts_class != 0 );
   CoreObject *self = ts_class->asClass()->createInstance();
   self->setUserData( ts1 );
   vm->retval( self );
}

//==================================================================
// Timezone

/*#
   @class TimeZone
   @brief TimeZone enumeration and services.

   This class proves the list of managed timezones and various services
   needed to handle them.

   The enumerative part contains the following constants, representing west,
   east and some named timezones:

   - local: Special local zone (unassigned, but relative to current location).
   - UTC or GMT
   - E1 to E12 (+1h to +12h)

   - W1 to W12 (-1h to -12h)
   - EDT
   - EST
   - CDT
   - CST
   - MDT
   - MST
   - PDT
   - PST

   - NFT
   - ACDT
   - ACST
   - HAT
   - NST

   - NONE: No/neutral/unknown timezone.
*/

/*#
   @method getDisplacement TimeZone
   @brief Returns the distance in minutes from the GMT time of a given timezone
   @param tz A time zone code.
   @return A relative time distance in minutes.

   This static method, callable directly on the TimeZone class, returns the
   time displacement of a determined time zone with respect to GMT.
*/

FALCON_FUNC  TimeZone_getDisplacement ( ::Falcon::VMachine *vm )
{
   // verify that the string is valid
   Item *i_tz = vm->param(0);
   if( i_tz == 0 || ! i_tz->isOrdinal() )
   {
      vm->raiseModError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).
         extra( "N" ) ) );
      return;
   }
   int tz = (int) i_tz->forceInteger();
   if ( tz < 0 || tz >= 32 )
   {
      vm->raiseModError( new ParamError( ErrorParam( e_param_range, __LINE__ ).origin( e_orig_runtime ).
         extra( "Invalid timezone" ) ) );
      return;
   }

   int16 hours, minutes;
   TimeStamp::getTZDisplacement( (TimeZone) tz, hours, minutes );
   vm->retval( (int64) (hours *60 + minutes) );
}

/*#
   @method describe TimeZone
   @brief Returns a descriptive string naming the required timezone.
   @param tz A time zone code.
   @return A timezone name.

   This static method, callable directly on the TimeZone class, returns a
   RFC 2822 compliant timezone name, given a timezone code. The "name" is
   in the format "+/-hhmm".
*/

FALCON_FUNC  TimeZone_describe ( ::Falcon::VMachine *vm )
{
   Item *i_tz = vm->param(0);
   if( i_tz == 0 || ! i_tz->isOrdinal() )
   {
      vm->raiseModError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).origin( e_orig_runtime ).
         extra( "N" ) ) );
      return;
   }
   int tz = (int) i_tz->forceInteger();
   if ( tz < 0 || tz >= 32 )
   {
      vm->raiseModError( new ParamError( ErrorParam( e_param_range, __LINE__ ).origin( e_orig_runtime ).
         extra( "Invalid timezone" ) ) );
      return;
   }

   vm->retval( new GarbageString( vm, TimeStamp::getRFC2822_ZoneName( (TimeZone) tz ) ) );
}

/*#
   @method getLocal TimeZone
   @brief Return local time zone code.
   @return A time zone code coresponding to the system local timezone.

   To get a descriptive name of local timezone, use:

   @code
      TimeZone.describe( TimeZone.getLocal() )
   @endcode
*/

FALCON_FUNC  TimeZone_getLocal ( ::Falcon::VMachine *vm )
{
   vm->retval( (int64) Sys::Time::getLocalTimeZone() );
}

}}

/* end of time_ext.cpp */

Generated by  Doxygen 1.6.0   Back to index