Skip to content

Commit c9a9200

Browse files
committed
merged branch stloyd/datetime_fixes (PR symfony#1485)
Commits ------- 3917ed7 Revert "* DateType, DateTimeType, TimeType: - a bit changed readability" c85b815 Fixed few issues with Date and Time: Discussion ---------- [Form] Fixed few issues with Date and Time Fixed few issues with Date and Time: * TimeType: - seconds are no longer populated if "with_seconds" = false - "widget = text" is now properly rendered (closes symfony#1480) * DateTimeToStringTransformer: - fixed using not default "format" (probably fix symfony#1183) * DateType, DateTimeType, TimeType: - fixed "input = datetime" and test covered
2 parents 311a9bd + 3917ed7 commit c9a9200

File tree

7 files changed

+209
-72
lines changed

7 files changed

+209
-72
lines changed

src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,12 @@ public function reverseTransform($value)
9595
}
9696

9797
try {
98-
$dateTime = new \DateTime(sprintf("%s %s", $value, $this->outputTimezone));
98+
$dateTime = new \DateTime($value, new \DateTimeZone($this->outputTimezone));
99+
100+
// Force value to be in same format as given to transform
101+
if ($value !== $dateTime->format($this->format)) {
102+
$dateTime = new \DateTime($dateTime->format($this->format), new \DateTimeZone($this->outputTimezone));
103+
}
99104

100105
if ($this->inputTimezone !== $this->outputTimezone) {
101106
$dateTime->setTimeZone(new \DateTimeZone($this->inputTimezone));

src/Symfony/Component/Form/Extension/Core/Type/TimeType.php

+40-33
Original file line numberDiff line numberDiff line change
@@ -28,51 +28,67 @@ class TimeType extends AbstractType
2828
*/
2929
public function buildForm(FormBuilder $builder, array $options)
3030
{
31+
$parts = array('hour', 'minute');
32+
$format = 'H:i:00';
33+
if ($options['with_seconds']) {
34+
$format = 'H:i:s';
35+
$parts[] = 'second';
36+
}
37+
3138
if ($options['widget'] === 'single_text') {
32-
$builder->appendClientTransformer(new DateTimeToStringTransformer($options['data_timezone'], $options['user_timezone'], 'H:i:s'));
33-
} else if ($options['widget'] === 'choice') {
34-
if (is_array($options['empty_value'])) {
35-
$options['empty_value'] = array_merge(array('hour' => null, 'minute' => null, 'second' => null), $options['empty_value']);
36-
} else {
37-
$options['empty_value'] = array('hour' => $options['empty_value'], 'minute' => $options['empty_value'], 'second' => $options['empty_value']);
38-
}
39+
$builder->appendClientTransformer(new DateTimeToStringTransformer($options['data_timezone'], $options['user_timezone'], $format));
40+
} else {
41+
$hourOptions = $minuteOptions = $secondOptions = array();
3942

40-
$builder
41-
->add('hour', $options['widget'], array(
43+
if ($options['widget'] === 'choice') {
44+
if (is_array($options['empty_value'])) {
45+
$options['empty_value'] = array_merge(array('hour' => null, 'minute' => null, 'second' => null), $options['empty_value']);
46+
} else {
47+
$options['empty_value'] = array('hour' => $options['empty_value'], 'minute' => $options['empty_value'], 'second' => $options['empty_value']);
48+
}
49+
50+
// Only pass a subset of the options to children
51+
$hourOptions = array(
4252
'choice_list' => new PaddedChoiceList(
4353
array_combine($options['hours'], $options['hours']), 2, '0', STR_PAD_LEFT
4454
),
4555
'empty_value' => $options['empty_value']['hour'],
4656
'required' => $options['required'],
47-
))
48-
->add('minute', $options['widget'], array(
57+
);
58+
$minuteOptions = array(
4959
'choice_list' => new PaddedChoiceList(
5060
array_combine($options['minutes'], $options['minutes']), 2, '0', STR_PAD_LEFT
5161
),
5262
'empty_value' => $options['empty_value']['minute'],
5363
'required' => $options['required'],
54-
))
64+
);
65+
66+
if ($options['with_seconds']) {
67+
$secondOptions = array(
68+
'choice_list' => new PaddedChoiceList(
69+
array_combine($options['seconds'], $options['seconds']), 2, '0', STR_PAD_LEFT
70+
),
71+
'empty_value' => $options['empty_value']['second'],
72+
'required' => $options['required'],
73+
);
74+
}
75+
}
76+
77+
$builder
78+
->add('hour', $options['widget'], $hourOptions)
79+
->add('minute', $options['widget'], $minuteOptions)
5580
;
5681

5782
if ($options['with_seconds']) {
58-
$builder->add('second', $options['widget'], array(
59-
'choice_list' => new PaddedChoiceList(
60-
array_combine($options['seconds'], $options['seconds']), 2, '0', STR_PAD_LEFT
61-
),
62-
'empty_value' => $options['empty_value']['second'],
63-
'required' => $options['required'],
64-
));
83+
$builder->add('second', $options['widget'], $secondOptions);
6584
}
66-
}
6785

68-
$parts = array('hour', 'minute');
69-
if ($options['with_seconds']) {
70-
$parts[] = 'second';
86+
$builder->appendClientTransformer(new DateTimeToArrayTransformer($options['data_timezone'], $options['user_timezone'], $parts, $options['widget'] === 'text'));
7187
}
7288

7389
if ($options['input'] === 'string') {
7490
$builder->appendNormTransformer(new ReversedTransformer(
75-
new DateTimeToStringTransformer($options['data_timezone'], $options['data_timezone'], 'H:i:s')
91+
new DateTimeToStringTransformer($options['data_timezone'], $options['data_timezone'], $format)
7692
));
7793
} else if ($options['input'] === 'timestamp') {
7894
$builder->appendNormTransformer(new ReversedTransformer(
@@ -84,15 +100,6 @@ public function buildForm(FormBuilder $builder, array $options)
84100
));
85101
}
86102

87-
if ($options['widget'] !== 'single_text') {
88-
$builder->appendClientTransformer(new DateTimeToArrayTransformer(
89-
$options['data_timezone'],
90-
$options['user_timezone'],
91-
$parts,
92-
$options['widget'] === 'text'
93-
));
94-
}
95-
96103
$builder
97104
->setAttribute('widget', $options['widget'])
98105
->setAttribute('with_seconds', $options['with_seconds'])

tests/Symfony/Tests/Component/Form/AbstractLayoutTest.php

+32-1
Original file line numberDiff line numberDiff line change
@@ -1512,6 +1512,37 @@ public function testTimeWithSeconds()
15121512
);
15131513
}
15141514

1515+
public function testTimeText()
1516+
{
1517+
$form = $this->factory->createNamed('time', 'na&me', '04:05:06', array(
1518+
'property_path' => 'name',
1519+
'input' => 'string',
1520+
'widget' => 'text',
1521+
));
1522+
1523+
$this->assertWidgetMatchesXpath($form->createView(), array(),
1524+
'/div
1525+
[
1526+
./input
1527+
[@type="text"]
1528+
[@id="na&me_hour"]
1529+
[@name="na&me[hour]"]
1530+
[@value="04"]
1531+
[@size="1"]
1532+
[@required="required"]
1533+
/following-sibling::input
1534+
[@type="text"]
1535+
[@id="na&me_minute"]
1536+
[@name="na&me[minute]"]
1537+
[@value="05"]
1538+
[@size="1"]
1539+
[@required="required"]
1540+
]
1541+
[count(./input)=2]
1542+
'
1543+
);
1544+
}
1545+
15151546
public function testTimeSingleText()
15161547
{
15171548
$form = $this->factory->createNamed('time', 'na&me', '04:05:06', array(
@@ -1524,7 +1555,7 @@ public function testTimeSingleText()
15241555
'/input
15251556
[@type="text"]
15261557
[@name="na&me"]
1527-
[@value="04:05:06"]
1558+
[@value="04:05:00"]
15281559
'
15291560
);
15301561
}

tests/Symfony/Tests/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php

+40-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,20 @@ public function testTransform()
2929
$this->assertEquals($output, $transformer->transform($input));
3030
}
3131

32+
/**
33+
* @dataProvider getFormatAndDateTime
34+
*/
35+
public function testTransformRandomFormat($format, $datetime)
36+
{
37+
$transformer = new DateTimeToStringTransformer('UTC', 'UTC', $format);
38+
39+
$input = new \DateTime($datetime);
40+
$output = clone $input;
41+
$output->setTimezone(new \DateTimeZone('UTC'));
42+
43+
$this->assertEquals($output->format($format), $transformer->transform($input));
44+
}
45+
3246
public function testTransform_empty()
3347
{
3448
$transformer = new DateTimeToStringTransformer();
@@ -40,7 +54,7 @@ public function testTransform_differentTimezones()
4054
{
4155
$transformer = new DateTimeToStringTransformer('Asia/Hong_Kong', 'America/New_York', 'Y-m-d H:i:s');
4256

43-
$input = new \DateTime('2010-02-03 04:05:06 America/New_York');
57+
$input = new \DateTime('2010-02-03 12:05:06 America/New_York');
4458
$output = $input->format('Y-m-d H:i:s');
4559
$input->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
4660

@@ -66,6 +80,31 @@ public function testReverseTransform()
6680
$this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input, null));
6781
}
6882

83+
/**
84+
* @dataProvider getFormatAndDateTime
85+
*/
86+
public function testReverseTransformRandomFormat($format, $datetime)
87+
{
88+
$reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', $format);
89+
90+
$dateTime = new \DateTime($datetime);
91+
$input = $dateTime->format($format);
92+
93+
$this->assertDateTimeEquals($dateTime, $reverseTransformer->reverseTransform($input, null));
94+
}
95+
96+
public function getFormatAndDateTime()
97+
{
98+
return array(
99+
array('Y-m-d H:i:s', '2010-02-03 04:05:06 UTC'),
100+
array('Y-m-d H:i:00', '2010-02-03 04:05:00 UTC'),
101+
array('Y-m-d', '2010-02-03 UTC'),
102+
array('d-m-Y', '03-02-2010 UTC'),
103+
array('H:i:s', '04:05:06 UTC'),
104+
array('H:i:00', '04:05:00 UTC'),
105+
);
106+
}
107+
69108
public function testReverseTransform_empty()
70109
{
71110
$reverseTransformer = new DateTimeToStringTransformer();

tests/Symfony/Tests/Component/Form/Extension/Core/Type/DateTimeTypeTest.php

+20-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ public function testSubmit_differentTimezones()
136136
'user_timezone' => 'Pacific/Tahiti',
137137
'date_widget' => 'choice',
138138
'time_widget' => 'choice',
139-
// don't do this test with DateTime, because it leads to wrong results!
140139
'input' => 'string',
141140
'with_seconds' => true,
142141
));
@@ -161,6 +160,26 @@ public function testSubmit_differentTimezones()
161160
$this->assertEquals($dateTime->format('Y-m-d H:i:s'), $form->getData());
162161
}
163162

163+
public function testSubmit_differentTimezonesDateTime()
164+
{
165+
$form = $this->factory->create('datetime', null, array(
166+
'data_timezone' => 'America/New_York',
167+
'user_timezone' => 'Pacific/Tahiti',
168+
'widget' => 'single_text',
169+
'input' => 'datetime',
170+
));
171+
172+
$dateTime = new \DateTime('2010-06-02 03:04:05 America/New_York');
173+
174+
$form->bind('2010-06-02 03:04:05');
175+
176+
$outputTime = new \DateTime('2010-06-02 03:04:00 Pacific/Tahiti');
177+
$outputTime->setTimezone(new \DateTimeZone('America/New_York'));
178+
179+
$this->assertDateTimeEquals($outputTime, $form->getData());
180+
$this->assertEquals('2010-06-02 03:04:00', $form->getClientData());
181+
}
182+
164183
public function testSubmit_stringSingleText()
165184
{
166185
$form = $this->factory->create('datetime', null, array(

tests/Symfony/Tests/Component/Form/Extension/Core/Type/DateTypeTest.php

+17-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ public function testSetData_differentTimezones()
183183
$form = $this->factory->create('date', null, array(
184184
'data_timezone' => 'America/New_York',
185185
'user_timezone' => 'Pacific/Tahiti',
186-
// don't do this test with DateTime, because it leads to wrong results!
187186
'input' => 'string',
188187
'widget' => 'single_text',
189188
));
@@ -193,6 +192,23 @@ public function testSetData_differentTimezones()
193192
$this->assertEquals('01.06.2010', $form->getClientData());
194193
}
195194

195+
public function testSetData_differentTimezonesDateTime()
196+
{
197+
$form = $this->factory->create('date', null, array(
198+
'data_timezone' => 'America/New_York',
199+
'user_timezone' => 'Pacific/Tahiti',
200+
'input' => 'datetime',
201+
'widget' => 'single_text',
202+
));
203+
204+
$dateTime = new \DateTime('2010-06-02 America/New_York');
205+
206+
$form->setData($dateTime);
207+
208+
$this->assertDateTimeEquals($dateTime, $form->getData());
209+
$this->assertEquals('01.06.2010', $form->getClientData());
210+
}
211+
196212
public function testIsYearWithinRangeReturnsTrueIfWithin()
197213
{
198214
$this->markTestIncomplete('Needs to be reimplemented using validators');

0 commit comments

Comments
 (0)