@@ -49,6 +49,8 @@ static ID s_id_utc;
4949static ID s_id_getlocal ;
5050static ID s_id_BigDecimal ;
5151
52+ static VALUE s_Date ;
53+ static VALUE s_Date_GREGORIAN ; /* Date::GREGORIAN */
5254static VALUE s_IPAddr ;
5355static VALUE s_vmasks4 ;
5456static VALUE s_vmasks6 ;
@@ -937,6 +939,51 @@ pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
937939 return ip ;
938940}
939941
942+ /*
943+ * Document-class: PG::TextDecoder::Date < PG::SimpleDecoder
944+ *
945+ * This is a decoder class for conversion of PostgreSQL date type to Ruby Date values.
946+ *
947+ * Dates are expected in ISO format (+YYYY-MM-DD+), which is PostgreSQL's default DateStyle.
948+ * Other formats, BC dates, years beyond 9999 and the special values +infinity+ and +-infinity+
949+ * are returned as String.
950+ *
951+ * As soon as this class is used, it requires the ruby standard library 'date'.
952+ */
953+ static VALUE
954+ pg_text_dec_date (t_pg_coder * conv , const char * val , int len , int tuple , int field , int enc_idx )
955+ {
956+ if (len == 10
957+ && isdigit (val [0 ]) && isdigit (val [1 ]) && isdigit (val [2 ]) && isdigit (val [3 ])
958+ && val [4 ] == '-' && isdigit (val [5 ]) && isdigit (val [6 ])
959+ && val [7 ] == '-' && isdigit (val [8 ]) && isdigit (val [9 ])
960+ ) {
961+ int year = str2_to_int (val ) * 100 + str2_to_int (val + 2 );
962+ int mon = str2_to_int (val + 5 );
963+ int day = str2_to_int (val + 8 );
964+
965+ return rb_funcall (s_Date , s_id_new , 4 , INT2NUM (year ), INT2NUM (mon ), INT2NUM (day ), s_Date_GREGORIAN );
966+ }
967+
968+ return pg_text_dec_string (conv , val , len , tuple , field , enc_idx );
969+ }
970+
971+ /* called per autoload when TextDecoder::Date is used */
972+ static VALUE
973+ init_pg_text_decoder_date (VALUE rb_mPG_TextDecoder )
974+ {
975+ rb_require ("date" );
976+ rb_gc_register_address (& s_Date );
977+ rb_gc_register_address (& s_Date_GREGORIAN );
978+ s_Date = rb_const_get (rb_cObject , rb_intern ("Date" ));
979+ s_Date_GREGORIAN = rb_const_get (s_Date , rb_intern ("GREGORIAN" ));
980+
981+ /* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Date", rb_cPG_SimpleDecoder ); */
982+ pg_define_coder ( "Date" , pg_text_dec_date , rb_cPG_SimpleDecoder , rb_mPG_TextDecoder );
983+
984+ return Qnil ;
985+ }
986+
940987/* called per autoload when TextDecoder::Inet is used */
941988static VALUE
942989init_pg_text_decoder_inet (VALUE rb_mPG_TextDecoder )
@@ -982,6 +1029,7 @@ init_pg_text_decoder(void)
9821029
9831030 /* This module encapsulates all decoder classes with text input format */
9841031 rb_mPG_TextDecoder = rb_define_module_under ( rb_mPG , "TextDecoder" );
1032+ rb_define_private_method (rb_singleton_class (rb_mPG_TextDecoder ), "init_date" , init_pg_text_decoder_date , 0 );
9851033 rb_define_private_method (rb_singleton_class (rb_mPG_TextDecoder ), "init_inet" , init_pg_text_decoder_inet , 0 );
9861034 rb_define_private_method (rb_singleton_class (rb_mPG_TextDecoder ), "init_numeric" , init_pg_text_decoder_numeric , 0 );
9871035
0 commit comments