为了账号安全,请及时绑定邮箱和手机立即绑定

用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(一B)

标签:
Android iOS C++

2) 日期操作函数:
这些函数都和日期操作相关,具体请参考代码,注释应该比较清楚的。

/*
blf: 函数参数都是以指针方式传入(java或c#中就为传引用,swig将指针会转换为类对象,所有类对象在java和c#中都是传引用的.
     c#支持struct,是值类型

    c#还支持参数的ref和out方式,可以将值类型以传引用方式输出到参数中,相当于c中的指针

    经验之谈:除非在c/c++中你使用shared_ptr等智能指针,否则千万不要在函数或成员方法中malloc或new一个新对象然后return出来。
    比较好的方式还是通过参数传指针或引用方式来返回更新的数据。
*/
void date_set(SDate* ret,int year,int month,int day)
{
   assert(ret);
   ret->year = year;
   ret->month = month;
   ret->day = day;
}

/*
blf: 获取当前的年月日
*/
void date_get_now(SDate* ret)
{
   assert(ret);

   //time()此函数会返回从公元 1970 年1 月1 日的UTC 时间从0 时0 分0 秒算起到现在所经过的秒数。
   //记住:是秒数,而不是毫秒数(很多语言返回的是毫秒数,crt中是以秒为单位的)
   //如果t 并非空指针的话,此函数也会将返回值存到t指针所指的内存
   time_t t;
   time(&t);

   //转换到当前系统的本地时间
   struct tm* timeInfo;
   timeInfo = localtime(&t);

   //tm结构中的年份是从1900开始到今天的年数,因此需要加上1900
   ret->year  =  timeInfo->tm_year + 1900;

   //月份是 0 base的,我们按照1-12的方式来计算,因此加1
   ret->month =  timeInfo->tm_mon + 1;

   ret->day   =  timeInfo->tm_mday;
}

/*
blf: 是否相等
*/
bool date_is_equal(const SDate* left,const SDate* right)
{
   assert(left&&right);
   return (left->year == right->year &&
           left->month == right->month &&
           left->day == right->day);
}

/*
blf: 计算两个年份之间的月数
*/
int date_get_month_count_from_year_range(int startYear,int endYear)
{
   int diff = endYear - startYear + 1;
   return diff * 12;
}

/*
blf: 将一维的数据表示映射成二维表示(年和月)
     startYear表示起始年,例如 2010年
     idx表示相对2010年开始的月份偏移量

     我们会在下面和后面代码中看到/ 和 %的多次使用
     可以理解为,将一维数据映射成二维行列表示的数据时,都可以使用这种方式

     下面这个函数用于月历区间选择控件,例如你有个数据库查询需求,可以查询
     当前年月日----五年前的年1月1号之间的数据,此时在UITabelView或ListView时,就需要
     调用本函数来显示年月信息等
*/
void date_map_index_to_year_month(SDate* to,int startYear,int idx)
{
   assert(to);

   //每年有12个月,idx/12你可以看成每12个月进一位,加上startYear基准值,就可以获得当前年份
   to->year = startYear + idx / 12;

   //每年有12个月,idx%12你可以看成【0-11】之间循环,加1是因为我们的SDate结构是1-12表示的
   to->month = idx % 12 + 1;

   //至于day,这里为-1,我们在map中忽略该值,可以设置任意值
   to->day = -1;
}

/*
blf: 下面函数来源于linux实现,计算从某个时间点(年月日时分秒)到1970年0时0分0秒的时间差
参考url: http://blog.csdn.net/axx1611/article/details/1792827
*/
long mymktime (unsigned int year, unsigned int mon,
                      unsigned int day, unsigned int hour,
                      unsigned int min, unsigned int sec)
{
   if (0 >= (int) (mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
      mon += 12;      /* Puts Feb last since it has leap day */
      year -= 1;
   }

   return (((
                    (long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
                    year*365 - 719499
            )*24 + hour /* now have hours */
           )*60 + min /* now have minutes */
          )*60 + sec; /* finally seconds */
}

/*
blf: 下面函数一共实现了三个版本

     第一版: 不知道是我对c的mktime用法错误还是有bug(理论上不可能,因为ios和android中都存在问题)
             同一个时间点,例如2016年1月1日0时0分1秒与1970年1月1日0时0分0秒的时间差不一样。

     第二版: 使用ios自身的 NSCalendar对象计算时间差,这个计算是正确的,但是只能用在ios中

     第三版: http://blog.csdn.net/axx1611/article/details/1792827中的算法,来自于linux源码,ios/android中运行的很好

     为什么不用time_t而是使用long呢?
     这是因为android中使用swig将c/c++ 代码转换成java jni封装的函数时,time_t被封装成了对象。
     因为java不认识c的typedef结构,Swig将其转换为SWITGYPT_p_XXXXX类型的包装(经典的装箱/拆箱,每次操作都要进行装箱拆箱,很麻烦).
     time_t只是64位整型的typedef而已,因此转换为long后,经Swig转换后,对应为java的整型,这样操作起来比较简单

*/

long date_get_time_t(const SDate* d)
{
    assert(d);

    /*
     1、第一版
    struct tm date;
    //crt函数中year是基于1900年的偏移,因此要减去1900
    date.tm_year = d->year - 1900;

    //crt函数中月份是[0-11]表示的,我们使用[1-12]表示,因此要减去1
    date.tm_mon = d->month - 1;

    date.tm_mday = d->day;
    date.tm_hour = 0;
    date.tm_min = 0;
    date.tm_sec = 1;
    time_t seconds = mktime(&date);

    return (long)seconds;
    */

    /*
     2、第二版 ios NSCalendar对象计算时间差
     NSDateComponents *components = [[NSDateComponents alloc] init];

     [components setDay:d->day]; // Monday
     [components setMonth:d->month]; // May
     [components setYear:d->year];

     NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

     NSDate *date = [gregorian dateFromComponents:components];

     return (time_t) [date timeIntervalSince1970];
     */

     /*
     3、网上Linux版本
     */
     return mymktime(d->year,d->month,d->day,0,0,1);
}

/*
blf: 根据delta计算月份,返回值存储在date结构中
     例如:当前年月为2015年1月份,delta为2,则返回2014年11月
*/
void date_get_prev_month(SDate* date, int delta)
{
   assert(date);

   if((date->month - delta) < 1)
   {
      //条件: 假设为2015年1月,delta = 2
      //因为: 1-2 = -1 < 1
      //所以: 年数 = 2015 - 1 = 2014 月份 = 12 + 1 - 2 = 11
      date->year--;
      date->month = 12 + date->month - delta;
   }
   else
      date->month = date->month - delta;
}

/*
blf: 根据delta计算出月份,返回值存储在date结构中
     例如:当前年月为2015年11月份,delta为2,则返回2016年1月
*/
void date_get_next_month(SDate* date, int delta)
{
   assert(date);
   if((date->month + delta) > 12)
   {
      //条件: 假设为2015年11月,delta = 2
      //因为: 11 + 2 = 13 > 12
      //所以: 年数 = 2015 + 1 = 2016 月份 = 11 + 2 - 12 = 1
      date->year++;
      date->month = date->month + delta - 12;
   }
   else
      date->month = date->month + delta;
}

/*
blf: 根据输入年份,判断是否是闰年
     固定算法:判断闰年的方法是该年能被4整除并且不能被100整除,或者是可以被400整除
*/
int date_get_leap(int year)
{
   if(((year % 4 == 0) && (year % 100) != 0)  (year % 400 == 0))
      return 1;
   return 0;
}

/*
blf: 辅助函数,用于计算某年某月的某天是星期几
*/
int date_get_days(const SDate* date)
{
   assert(date);
   int day_table[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
   int i = 0, total = 0;
   for(i = 0; i < date->month; i++)
      total += day_table[i];
   return total + date->day + date_get_leap(date->year);
}

/*
blf: 用于计算某年某月的某天是星期几,调用上面函数
     这些算法比较固定,具体原理也不需要太了解,因为我也不清楚。
*/
int date_get_week(const SDate* date)
{
   assert(date);
   return ((date->year - 1 + (date->year - 1) / 4 - (date->year - 1) / 100 +
            (date->year - 1) / 400 + date_get_days(date) )% 7);
}

/*
blf: 用于计算某个月的天数
*/
int date_get_month_of_day(int year, int month)
{
   switch(month)
   {
      case 1:
      case 3:
      case 5:
      case 7:
      case 8:
      case 10:
      case 12: return 31;
      case 4:
      case 6:
      case 9:
      case 11: return 30;
   }
   //blf:2月比较特别,要进行闰年判断
   return 28 + date_get_leap(year);
}
点击查看更多内容
3人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消