datetimepicker 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/app/assets/javascripts/datetimepicker.js.coffee +12 -0
- data/app/assets/javascripts/datetimepicker/bootstrap_datepicker.js +401 -0
- data/app/assets/javascripts/datetimepicker/bootstrap_timepicker.js +800 -0
- data/app/assets/stylesheets/_datetimepicker.css.scss +2 -0
- data/app/assets/stylesheets/datetimepicker/bootstrap_datepicker.css +156 -0
- data/app/assets/stylesheets/datetimepicker/bootstrap_timepicker.css +81 -0
- data/datetimepicker.gemspec +17 -0
- data/lib/datetimepicker.rb +14 -0
- data/lib/datetimepicker/activerecord.rb +122 -0
- data/lib/datetimepicker/date_and_time_manipulator.rb +84 -0
- data/lib/datetimepicker/date_formats.rb +2 -0
- data/lib/datetimepicker/engine.rb +5 -0
- data/lib/datetimepicker/simple_form/inputs/datetimepicker_input.rb +29 -0
- data/lib/datetimepicker/version.rb +3 -0
- metadata +65 -0
@@ -0,0 +1,156 @@
|
|
1
|
+
/*!
|
2
|
+
* Datepicker for Bootstrap
|
3
|
+
*
|
4
|
+
* Copyright 2012 Stefan Petre
|
5
|
+
* Licensed under the Apache License v2.0
|
6
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
*
|
8
|
+
*/
|
9
|
+
.datepicker {
|
10
|
+
top: 0;
|
11
|
+
left: 0;
|
12
|
+
padding: 4px;
|
13
|
+
margin-top: 1px;
|
14
|
+
-webkit-border-radius: 4px;
|
15
|
+
-moz-border-radius: 4px;
|
16
|
+
border-radius: 4px;
|
17
|
+
/*.dow {
|
18
|
+
border-top: 1px solid #ddd !important;
|
19
|
+
}*/
|
20
|
+
}
|
21
|
+
.datepicker:before {
|
22
|
+
content: '';
|
23
|
+
display: inline-block;
|
24
|
+
border-left: 7px solid transparent;
|
25
|
+
border-right: 7px solid transparent;
|
26
|
+
border-bottom: 7px solid #ccc;
|
27
|
+
border-bottom-color: rgba(0, 0, 0, 0.2);
|
28
|
+
position: absolute;
|
29
|
+
top: -7px;
|
30
|
+
left: 6px;
|
31
|
+
}
|
32
|
+
.datepicker:after {
|
33
|
+
content: '';
|
34
|
+
display: inline-block;
|
35
|
+
border-left: 6px solid transparent;
|
36
|
+
border-right: 6px solid transparent;
|
37
|
+
border-bottom: 6px solid #ffffff;
|
38
|
+
position: absolute;
|
39
|
+
top: -6px;
|
40
|
+
left: 7px;
|
41
|
+
}
|
42
|
+
.datepicker > div {
|
43
|
+
display: none;
|
44
|
+
}
|
45
|
+
.datepicker table {
|
46
|
+
width: 100%;
|
47
|
+
margin: 0;
|
48
|
+
}
|
49
|
+
.datepicker td, .datepicker th {
|
50
|
+
text-align: center;
|
51
|
+
width: 20px;
|
52
|
+
height: 20px;
|
53
|
+
-webkit-border-radius: 4px;
|
54
|
+
-moz-border-radius: 4px;
|
55
|
+
border-radius: 4px;
|
56
|
+
}
|
57
|
+
.datepicker td.day:hover {
|
58
|
+
background: #eeeeee;
|
59
|
+
cursor: pointer;
|
60
|
+
}
|
61
|
+
.datepicker td.old, .datepicker td.new {
|
62
|
+
color: #999999;
|
63
|
+
}
|
64
|
+
.datepicker td.active, .datepicker td.active:hover {
|
65
|
+
background-color: #006dcc;
|
66
|
+
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
|
67
|
+
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
|
68
|
+
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
|
69
|
+
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
|
70
|
+
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
|
71
|
+
background-image: linear-gradient(top, #0088cc, #0044cc);
|
72
|
+
background-repeat: repeat-x;
|
73
|
+
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
|
74
|
+
border-color: #0044cc #0044cc #002a80;
|
75
|
+
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
76
|
+
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
77
|
+
color: #fff;
|
78
|
+
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
79
|
+
}
|
80
|
+
.datepicker td.active:hover,
|
81
|
+
.datepicker td.active:hover:hover,
|
82
|
+
.datepicker td.active:active,
|
83
|
+
.datepicker td.active:hover:active,
|
84
|
+
.datepicker td.active.active,
|
85
|
+
.datepicker td.active:hover.active,
|
86
|
+
.datepicker td.active.disabled,
|
87
|
+
.datepicker td.active:hover.disabled,
|
88
|
+
.datepicker td.active[disabled],
|
89
|
+
.datepicker td.active:hover[disabled] {
|
90
|
+
background-color: #0044cc;
|
91
|
+
}
|
92
|
+
.datepicker td.active:active,
|
93
|
+
.datepicker td.active:hover:active,
|
94
|
+
.datepicker td.active.active,
|
95
|
+
.datepicker td.active:hover.active {
|
96
|
+
background-color: #003399 \9;
|
97
|
+
}
|
98
|
+
.datepicker td span {
|
99
|
+
display: block;
|
100
|
+
width: 47px;
|
101
|
+
height: 54px;
|
102
|
+
line-height: 54px;
|
103
|
+
float: left;
|
104
|
+
margin: 2px;
|
105
|
+
cursor: pointer;
|
106
|
+
-webkit-border-radius: 4px;
|
107
|
+
-moz-border-radius: 4px;
|
108
|
+
border-radius: 4px;
|
109
|
+
}
|
110
|
+
.datepicker td span:hover {
|
111
|
+
background: #eeeeee;
|
112
|
+
}
|
113
|
+
.datepicker td span.active {
|
114
|
+
background-color: #006dcc;
|
115
|
+
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
|
116
|
+
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
|
117
|
+
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
|
118
|
+
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
|
119
|
+
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
|
120
|
+
background-image: linear-gradient(top, #0088cc, #0044cc);
|
121
|
+
background-repeat: repeat-x;
|
122
|
+
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
|
123
|
+
border-color: #0044cc #0044cc #002a80;
|
124
|
+
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
125
|
+
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
126
|
+
color: #fff;
|
127
|
+
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
128
|
+
}
|
129
|
+
.datepicker td span.active:hover,
|
130
|
+
.datepicker td span.active:active,
|
131
|
+
.datepicker td span.active.active,
|
132
|
+
.datepicker td span.active.disabled,
|
133
|
+
.datepicker td span.active[disabled] {
|
134
|
+
background-color: #0044cc;
|
135
|
+
}
|
136
|
+
.datepicker td span.active:active, .datepicker td span.active.active {
|
137
|
+
background-color: #003399 \9;
|
138
|
+
}
|
139
|
+
.datepicker td span.old {
|
140
|
+
color: #999999;
|
141
|
+
}
|
142
|
+
.datepicker th.switch {
|
143
|
+
width: 145px;
|
144
|
+
}
|
145
|
+
.datepicker thead tr:first-child th {
|
146
|
+
cursor: pointer;
|
147
|
+
}
|
148
|
+
.datepicker thead tr:first-child th:hover {
|
149
|
+
background: #eeeeee;
|
150
|
+
}
|
151
|
+
.input-append.date .add-on i, .input-prepend.date .add-on i {
|
152
|
+
display: block;
|
153
|
+
cursor: pointer;
|
154
|
+
width: 16px;
|
155
|
+
height: 16px;
|
156
|
+
}
|
@@ -0,0 +1,81 @@
|
|
1
|
+
.bootstrap-timepicker.dropdown-menu {
|
2
|
+
border-radius: 4px 4px 4px 4px;
|
3
|
+
display: none;
|
4
|
+
left: 0;
|
5
|
+
margin-top: 1px;
|
6
|
+
padding: 4px;
|
7
|
+
top: 0;
|
8
|
+
min-width: 10px;
|
9
|
+
}
|
10
|
+
.bootstrap-timepicker.dropdown-menu.open {
|
11
|
+
display: inline-block;
|
12
|
+
}
|
13
|
+
.bootstrap-timepicker.dropdown-menu:before {
|
14
|
+
border-bottom: 7px solid rgba(0, 0, 0, 0.2);
|
15
|
+
border-left: 7px solid transparent;
|
16
|
+
border-right: 7px solid transparent;
|
17
|
+
content: "";
|
18
|
+
left: 6px;
|
19
|
+
position: absolute;
|
20
|
+
top: -7px;
|
21
|
+
}
|
22
|
+
.bootstrap-timepicker.dropdown-menu:after {
|
23
|
+
border-bottom: 6px solid #FFFFFF;
|
24
|
+
border-left: 6px solid transparent;
|
25
|
+
border-right: 6px solid transparent;
|
26
|
+
content: "";
|
27
|
+
left: 7px;
|
28
|
+
position: absolute;
|
29
|
+
top: -6px;
|
30
|
+
}
|
31
|
+
.bootstrap-timepicker.modal {
|
32
|
+
margin-left: -100px;
|
33
|
+
margin-top: 0;
|
34
|
+
top: 30%;
|
35
|
+
width: 200px;
|
36
|
+
}
|
37
|
+
.bootstrap-timepicker.modal .modal-content {
|
38
|
+
padding: 0;
|
39
|
+
}
|
40
|
+
.bootstrap-timepicker table {
|
41
|
+
margin: 0;
|
42
|
+
width: 100%;
|
43
|
+
}
|
44
|
+
.bootstrap-timepicker table td {
|
45
|
+
height: 30px;
|
46
|
+
margin: 0;
|
47
|
+
padding: 2px;
|
48
|
+
text-align: center;
|
49
|
+
}
|
50
|
+
.bootstrap-timepicker table td span {
|
51
|
+
width: 100%;
|
52
|
+
}
|
53
|
+
.bootstrap-timepicker table td a {
|
54
|
+
border: 1px solid transparent;
|
55
|
+
display: inline-block;
|
56
|
+
margin: 0;
|
57
|
+
outline: 0 none;
|
58
|
+
padding: 8px 0;
|
59
|
+
width: 3em;
|
60
|
+
}
|
61
|
+
.bootstrap-timepicker table td a:hover {
|
62
|
+
background-color: #EEEEEE;
|
63
|
+
border-color: #DDDDDD;
|
64
|
+
border-radius: 4px 4px 4px 4px;
|
65
|
+
}
|
66
|
+
.bootstrap-timepicker table td a i {
|
67
|
+
margin-top: 2px;
|
68
|
+
}
|
69
|
+
.bootstrap-timepicker table td input {
|
70
|
+
margin: 0;
|
71
|
+
text-align: center;
|
72
|
+
width: 25px;
|
73
|
+
}
|
74
|
+
.bootstrap-timepicker-component .add-on {
|
75
|
+
cursor: pointer;
|
76
|
+
}
|
77
|
+
.bootstrap-timepicker-component .add-on i {
|
78
|
+
display: block;
|
79
|
+
height: 16px;
|
80
|
+
width: 16px;
|
81
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/datetimepicker/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Daniel Ott"]
|
6
|
+
gem.email = ["danott@marshill.com"]
|
7
|
+
gem.description = %q{Custom field for individual setting of date and time for Rails :datetime attributes.}
|
8
|
+
gem.summary = %q{Custom field for individual setting of date and time for Rails :datetime attributes.}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "datetimepicker"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Datetimepicker::VERSION
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "datetimepicker/version"
|
2
|
+
|
3
|
+
module Datetimepicker
|
4
|
+
autoload :DateAndTimeManipulator, "datetimepicker/date_and_time_manipulator"
|
5
|
+
|
6
|
+
class Engine < ::Rails::Engine
|
7
|
+
require "datetimepicker/engine"
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
require "datetimepicker/date_formats"
|
13
|
+
require "datetimepicker/activerecord"
|
14
|
+
require "datetimepicker/simple_form/inputs/datetimepicker_input"
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# Extension made to ActiveRecord::Base to handle datetimepickers dynamic methods.
|
2
|
+
ActiveRecord::Base.class_eval do
|
3
|
+
|
4
|
+
# Public: All the available :datetime columns for this model.
|
5
|
+
#
|
6
|
+
# Returns an Array of attribute names.
|
7
|
+
def self.datetime_columns
|
8
|
+
@datetime_columns ||= columns.select { |c| c.type == :datetime }.map(&:name)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Public: we need to retain all of ActiveRecord's existing respond_to? fun.
|
12
|
+
alias_method :active_record_original_respond_to?, :respond_to?
|
13
|
+
|
14
|
+
# Public: ActiveRecord::Base should recognize our dynamic methods as existing.
|
15
|
+
#
|
16
|
+
# This respond_to? override will do exactly that. If the method being
|
17
|
+
# tested does not match any of these, the pre-exisiting respond_to? for
|
18
|
+
# ActiveRecord::Base is called to continue looking.
|
19
|
+
def respond_to?(method, include_private = false)
|
20
|
+
(method =~ datetimepicker_method_regex) || active_record_original_respond_to?(method, include_private)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# Private: we need to retain all of ActiveRecord's existing method_missing fun.
|
26
|
+
alias_method :active_record_original_method_missing, :method_missing
|
27
|
+
|
28
|
+
# Private: handle missing methods for datetimepickers.
|
29
|
+
#
|
30
|
+
# This method_missing override will do exactly that. If the method being
|
31
|
+
# tested does not match any of these, the pre-exisiting method_missing for
|
32
|
+
# ActiveRecord::Base is called to continue looking
|
33
|
+
def method_missing(method, *args, &block)
|
34
|
+
if method =~ datetimepicker_method_regex
|
35
|
+
# First matched group in datetimepicker_method_regex is the attribute
|
36
|
+
# we're trying to set/get.
|
37
|
+
attribute_name = $1
|
38
|
+
|
39
|
+
# Second matched group in datetimepicker_method_regex is the method
|
40
|
+
# on datetimepicker that is trying to be sent.
|
41
|
+
# Possible values: "date", "date=", "time", "time=",
|
42
|
+
# "date_before_type_cast", "time_before_type_cast"
|
43
|
+
datetimepicker_method = $2
|
44
|
+
|
45
|
+
# When simple_form is generating inputs, it's looking for the value of
|
46
|
+
# "#{attribute_name}_datepicker_date_before_type_cast". Since this
|
47
|
+
# "column" we're generating inputs for is dynamic, we can cut that part
|
48
|
+
# out to keep things working the way we expect.
|
49
|
+
datetimepicker_method.gsub!("_before_type_cast", "")
|
50
|
+
|
51
|
+
send(:datetimepicker_proxy, attribute_name, datetimepicker_method, *args)
|
52
|
+
else
|
53
|
+
active_record_original_method_missing(method, *args, &block)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Private: the regex that matches datetimepicker's dynamic methods.
|
58
|
+
#
|
59
|
+
# The method we want to allow to be called dynamically:
|
60
|
+
#
|
61
|
+
# - attribute_name_datetimepicker_date
|
62
|
+
# - attribute_name_datetimepicker_date=
|
63
|
+
# - attribute_name_datetimepicker_date_before_type_cast
|
64
|
+
# - attribute_name_datetimepicker_time
|
65
|
+
# - attribute_name_datetimepicker_time=
|
66
|
+
# - attribute_name_datetimepicker_time_before_type_cast
|
67
|
+
#
|
68
|
+
# Returns a Regex
|
69
|
+
def datetimepicker_method_regex
|
70
|
+
/^(\w+)_datetimepicker_((?:date|time)(?:_before_type_cast)?=?)$/
|
71
|
+
end
|
72
|
+
|
73
|
+
# Private: does a datetime column exist for this attribute_name?
|
74
|
+
#
|
75
|
+
# attribute_name - the column we're testing for.
|
76
|
+
#
|
77
|
+
# Returns a Boolean.
|
78
|
+
def datetimepicker_column?(attribute_name)
|
79
|
+
self.class.datetime_columns.include?(attribute_name.to_s)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Private: Proxy method written so we can utilize dynamic methods for
|
83
|
+
# manipulating columns of type datetime by their date and time independently.
|
84
|
+
#
|
85
|
+
# Getters get date/time values.
|
86
|
+
#
|
87
|
+
# Setters set date/time values, and update the datetime column.
|
88
|
+
#
|
89
|
+
# attribute_name - The active record attribute we're wrapping.
|
90
|
+
# datetimepicker_method - the message to pass along to manipulate the column
|
91
|
+
# using the Datetimepicker.
|
92
|
+
# args - Any attitional arguments to pass along to
|
93
|
+
# Datetimepicker.
|
94
|
+
#
|
95
|
+
# Examples
|
96
|
+
#
|
97
|
+
# datetimepicker_proxy(:created_at, "date=", "2012/01/01")
|
98
|
+
#
|
99
|
+
# Returns mixed. Getters return gotten value. Setters return the new
|
100
|
+
# attribute_name value.
|
101
|
+
def datetimepicker_proxy(attribute_name, datetimepicker_method, *args)
|
102
|
+
if !datetimepicker_column?(attribute_name)
|
103
|
+
raise "Datetimepicker can only be used on columns of type :datetime"
|
104
|
+
end
|
105
|
+
|
106
|
+
# Datetimepicker won't work so good with a nil value.
|
107
|
+
attribute_value = send(attribute_name) || Time.now.beginning_of_hour
|
108
|
+
|
109
|
+
datetimepicker = Datetimepicker::DateAndTimeManipulator.new(attribute_value,
|
110
|
+
Time::DATE_FORMATS[:datetimepicker_date],
|
111
|
+
Time::DATE_FORMATS[:datetimepicker_time])
|
112
|
+
return_value = datetimepicker.send(datetimepicker_method, *args)
|
113
|
+
|
114
|
+
# Setters gonna set.
|
115
|
+
if datetimepicker_method =~ /=$/
|
116
|
+
return_value = write_attribute(attribute_name.to_sym, datetimepicker.datetime)
|
117
|
+
end
|
118
|
+
|
119
|
+
return_value
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Public: A simple structure for independently manipulating the date and time
|
2
|
+
# components of a TimeWithZone object, while maintining the the existing date
|
3
|
+
# and time information.
|
4
|
+
#
|
5
|
+
# datetime - an instance of DateTime/Time/TimeWithZone.
|
6
|
+
# date_format - A String containing the strftime format for setting/getting
|
7
|
+
# date component of datetime.
|
8
|
+
# time_format - A String containing the strftime format for setting/getting
|
9
|
+
# time component of datetime.
|
10
|
+
# Examples
|
11
|
+
#
|
12
|
+
# DateTimePicker.new(Post.first.created_at, "%Y/%m/%d", "%H:%M")
|
13
|
+
module Datetimepicker
|
14
|
+
class DateAndTimeManipulator < Struct.new(:datetime, :date_format, :time_format)
|
15
|
+
|
16
|
+
# Public: get the date component of datetime.
|
17
|
+
#
|
18
|
+
# Returns a String in the format of date_format.
|
19
|
+
def date
|
20
|
+
datetime.strftime(date_format)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Public: set the date component of datetime.
|
24
|
+
#
|
25
|
+
# new_date - The String representation of date component for datetime.
|
26
|
+
# The String should be in the format of date_format.
|
27
|
+
def date=(new_date)
|
28
|
+
self.datetime = parse_date_and_time(new_date, time)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Public: get the time component of datetime.
|
32
|
+
#
|
33
|
+
# Returns a String in the format of time_format.
|
34
|
+
def time
|
35
|
+
datetime.strftime(time_format)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Public: set the time component of datetime.
|
39
|
+
#
|
40
|
+
# new_time - The String representation of time component for datetime.
|
41
|
+
# The String should be in the format of time_format.
|
42
|
+
def time=(new_time)
|
43
|
+
self.datetime = parse_date_and_time(date, new_time)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# Private: create a new TimeWithZone from date and time Strings.
|
49
|
+
#
|
50
|
+
# date - A String of the date in the format of date_format
|
51
|
+
# time - A String of the time in the format of time_format.
|
52
|
+
#
|
53
|
+
# The following blog post was infinitely valuable in figuring out how to
|
54
|
+
# parse dates and times while maintaining a time zone in Rails.
|
55
|
+
#
|
56
|
+
# http://www.elabs.se/blog/36-working-with-time-zones-in-ruby-on-rails
|
57
|
+
#
|
58
|
+
# Returns an instance of TimeWithZone.
|
59
|
+
def parse_date_and_time(parse_date, parse_time)
|
60
|
+
Time.strptime(date_and_time_format(parse_date, parse_time),
|
61
|
+
date_and_time_format(date_format, time_format)).in_time_zone(Time.zone)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Private: generate strings for parsing datetime in a consistent way.
|
65
|
+
#
|
66
|
+
# date_component - A String of the date component of the date and time pair.
|
67
|
+
# time_component - A String of the time component of the date and time pair.
|
68
|
+
# separator - (optional) String used to concatenate the components.
|
69
|
+
#
|
70
|
+
# Examples
|
71
|
+
#
|
72
|
+
# date_and_time_format("%Y/%m/%d", "%H:%M")
|
73
|
+
# => "%Y/%m/%d %H:%M"
|
74
|
+
#
|
75
|
+
# date_and_time_format("2004/08/15", "16:23", "T")
|
76
|
+
# => "2004/0815T16:23"
|
77
|
+
#
|
78
|
+
# Returns a String.
|
79
|
+
def date_and_time_format(date_component, time_component, separator = " ")
|
80
|
+
"#{date_component}#{separator}#{time_component}"
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|