Перейти к содержимому

Europe moscow что это

  • автор:

Записки программиста

Часовые пояса обычно ассоциируются с чем-то невероятно сложным. Однако, как это часто бывает, если сесть и спокойно во всем разобраться, то проблема оказывается не такой уж большой. Особенно если положиться на проверенные решения, где уже реализована вся логика.

PostgreSQL предлагает два типа для хранения даты и времени — timestamp и timestamptz. Внутреннее представление данных типов абсолютно одинаковое. Это 64-х битные знаковые целые, хранящие время в микросекундах относительно 1-го января 2000-го года 00:00:00 UTC.

Отличие только в том, как они отображаются:

С timestamp все понятно, это же просто время в UTC. Однако timestamptz отображается в часовом поясе текущей сессии:

=# show time zone;
TimeZone
—————
Europe/Moscow

=# select ‘2021-10-01 12:34:56 Europe/Moscow’ :: timestamptz;
timestamptz
————————
2021-10-01 12:34:56+03

=# set time zone ‘+00’;
SET

=# select ‘2021-10-01 12:34:56 Europe/Moscow’ :: timestamptz;
timestamptz
————————
2021-10-01 09:34:56+00

Еще раз, ключевой момент — значение одно и то же! Но отображается оно по-разному в зависимости от параметров сессии.

Часовой пояс, используемый по умолчанию, определяется параметром timezone в файле postgresql.conf. Этот параметр прописывается утилитой initdb во время инициализации СУБД. Значение параметра определяется окружением, в котором был запущен initdb. Если параметр не указан в postgresql.conf, используется часовой пояс GMT.

Получить информацию о доступных именах часовых поясов можно так:

=# select * from pg_timezone_names where abbrev = ‘MSK’;
name | abbrev | utc_offset | is_dst
——————-+———+————+———
Europe/Moscow | MSK | 03:00:00 | f
Europe/Simferopol | MSK | 03:00:00 | f
W-SU | MSK | 03:00:00 | f

Отсюда мы узнаем, что для Europe/Moscow есть сокращение MSK. Сокращения можно использовать при преобразовании строки в timestamptz:

=# select ‘2021-10-01 12:34:56 MSK’ :: timestamptz;
timestamptz
————————
2021-10-01 12:34:56+03

Но команда set time zone принимает только полное имя часового пояса:

=# set time zone ‘MSK’;
ERROR: invalid value for parameter «TimeZone»: «MSK»

=# set time zone ‘Europe/Moscow’;
SET

Иногда нужно преобразовать timestamptz в timestamp или наоборот. Если делать это в лоб, то результат может получиться не тот, который вы ожидаете:

=# set time zone ‘+00’;
SET

=# select (‘2021-10-01 12:34:56 MSK’ :: timestamptz) :: timestamp;
timestamp
———————
2021-10-01 09:34:56

Как же так? Ведь я хотел отрезать информацию о таймзоне и получить 12:34:56! Но вспомним, что внутри timestamptz хранится просто как время в UTC. В момент, когда timestamptz кастуется в timestamp у PostgreSQL нет никакой возможности узнать, что изначально время было в Europe/Moscow. Поэтому он преобразует время в часовой пояс текущий сессии.

Домашнее задание: Вызовите now() и now() :: timestamp . Смените часовой пояс сессии и повторите эксперимент. Объясните результат.

Для решения описанной проблемы есть альтернативный синтаксис:

=# select (‘2021-10-01 12:34:56 Europe/Moscow’ :: timestamptz) ⏎
at time zone ‘Europe/Moscow’;
timezone
———————
2021-10-01 12:34:56

Или, что полностью эквивалентно, можно воспользоваться функцией timezone:

=# select timezone(‘Europe/Moscow’, ⏎
‘2021-10-01 12:34:56 Europe/Moscow’ :: timestamptz);
timezone
———————
2021-10-01 12:34:56

Для преобразования в обратную сторону есть перегруженная версия timezone, принимающая timestamp и возвращающая timestamptz:

=# set time zone ‘Europe/Moscow’;
SET

=# select timezone(‘Europe/Moscow’, ‘2021-10-01 12:34:56’ :: timestamp);
timezone
————————
2021-10-01 12:34:56+03

Синтаксис at time zone также работает для timestamp:

=# select (‘2021-10-01 12:34:56’ :: timestamp) ⏎
at time zone ‘Europe/Moscow’;
timezone
————————
2021-10-01 12:34:56+03

Когда вы работаете в UTC или каком-нибудь UTC+3, все просто и понятно. Но при использовании часового пояса вроде MSK все интереснее. Вот пример:

=# set time zone ‘Europe/Moscow’;
SET

=# select (timestamptz ‘2014 Oct 26 01:00:00 MSK’);
timestamptz
————————
2014-10-26 01:00:00+03

=# select (timestamptz ‘2014 Oct 26 01:00:00 MSK’) — interval ‘1 hour’;
?column?
————————
2014-10-26 01:00:00+04

Был час ночи. Отняли один час, и получили час ночи. Удобно, не правда ли?

Дело в том, что московское время несколько раз менялось в прошлом, и наверняка еще изменится в будущем. 26 октября 2014-го года часовой пояс MSK как раз изменился с UTC+4 на UTC+3, о чем PostgreSQL прямым текстом и говорит — обратите внимание на +03 и +04 в выводе. Аналогичные приколы вас ждут в часовых поясах, где есть перевод часов на летнее и зимнее время (daylight saving time, DST). В Москве сейчас не переводят часы, но до марта 2011-го года переводили.

Fun fact! Если у времени в конкретном часовом поясе могут быть «дырки», то как timezone(zone, timestamp) обрабатывает невозможное время, попадающие в эти «дырки»? В данном сценарии функция завершается успешно, при этом невозможное время преобразуется в ближайшее возможное.

Для timestamptz из прошлого PostgreSQL применяет правила для часового пояса, которые были актуальны на тот момент времени. Приведенный выше пример наглядно это демонстрирует. Другими словами, если сейчас в вашем часовом поясе время T, оно всегда будет временем T в этом часовом поясе, даже если в будущем правила изменятся. Для времени из будущего применяются последние известные правила. Это означает, что при обновлении PostgreSQL и/или системы могут появится новые правила для часовых поясов, и функции, использующие timestamptz, начнут возвращать другой результат. Впрочем, это касается не только времени из будущего. Также были прецеденты исторических корректировок часовых поясов.

Несмотря на написанное выше, volatility функций, работающих с timestamptz, не обязательно является STABLE. В качестве STABLE-функции, работающей с timestamptz, можно привести в пример date_trunc() . Дело в том, что ее работа зависит от параметров сессии. Кастинг timestamptz в timestamp является STABLE по той же причине. Однако функция timezone() не смотрит на параметры сессии. Ее возвращаемое значение зависит только от переданных аргументов, и потому функция является IMMUTABLE. PostgreSQL не будет возражать, если вы решите использовать ее в функциональных индексах. И при обновлении базы часовых поясов индексы могут разъехаться.

Fun fact! PostgreSQL имеет собственную базу часовых поясов. В исходном коде эта база называется tzdata.zi. Но также PostgreSQL можно собрать с флагом —with-system-tzdata= . Он говорит использовать вместо собственной базы системные TZif-файлы (RFC 8536) . Эти файлы обычно живут в /usr/share/zoneinfo. Чтобы узнать, какую базу использует PostgreSQL, нужно проверить, с какими флагами был собран используемый вами пакет. Эти флаги отображает команда pg_config —configure .

Все перечисленное важно понимать для решения практических задач.

Допустим, вам нужно строить агрегаты по дням или месяцам в конкретном часовом поясе. Оказывается, что самое простое и надежное решение — это преобразовать время в timestamp при помощи at time zone , и затем обращаться с timestamp как с обычным временем. Если нужно несколько часовых поясов, строим несколько агрегатов. Здесь предполагается, что вы не работаете с временем из далекого будущего и своевременно обновляетесь. В противном случае агрегаты рано или поздно сломаются, и починить их сможет только перестройка из сырых данных. Хранить последние — всегда хорошая мысль, как минимум, потому что требования к системе меняются, и возникает необходимость в новых агрегатах. Ну и баги в коде никто не отменял.

Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.

Europe/Moscow и Etc/GMT-3 — это одно и то же?

А вы ведь в PHP разбираетесь?
У меня в PHP.ini date.timezone = «Europe/Moscow», а в скрипте date_default_timezone_set(‘Etc/GMT-3’);
Что нужно сделать, чтобы они были одинаковыми?

Дед Мазай Гений (58121) PHP я не знаю, однако иногда отвечаю на вопросы по PHP. Думаю, надо убрать эту строку из скрипта. Попробуйте.

Остальные ответы
GMT-3 — это московское время. Это значит, что время по Гринвичу, плюс три часа.
Andry NevermindУченик (71) 5 лет назад
Europe/Moscow и Etc/GMT-3 — это одно и то же?
Кубин Мастер (2022) Ну если это касается времени, то это одно и то же.

Etc/UTC — это timezone в базе данных Olson-timezone-database ( TZ database), также известной как IANA-timezones-database, в которой все часовые пояса соответствуют единому соглашению об именовании: Area/Location .

Поскольку некоторые часовые пояса не могут быть отнесены к какой-либо области мира (например, континентам или океанам), была введена специальная область Etc ( и так далее). Это относится в основном к административным часовым поясам, таким как UTC .
Таким образом, в соответствии с Соглашением об именовании универсальное координированное время (зона) называется Etc/UTC в базе данных tz.

Для административных часовых поясов, отличных от UTC (например, GMT+4, GMT-8), база данных tz использует знаки в стиле POSIX в названиях зон. POSIX имеет положительные знаки для зон, которые находятся позади Гринвича (к западу от Гринвича), и отрицательные знаки для зон, которые находятся впереди Гринвича (к востоку от Гринвича).

POSIX-стилевые знаки в часовых поясах противоположны определению часовых поясов в ныне широко распространенном и в основном используемом ISO 8601 . В формате ISO 8601 timezone отрицательные знаки указывают на то, что зона находится позади UTC (к западу от Гринвича), а положительные знаки указывают на то, что зона находится впереди UTC (к востоку от Гринвича). Это то, что стало стандартным использованием в наши дни.

Возможными причинами противоположного определения в POSIX являются:

POSIX является частью UNIX, который был разработан в USA, который находится за UTC (к западу от Гринвича). Формат POSIX позволяет представлять часовые пояса US как EST5, PST8, то есть опуская знак ( + ).
Как правило, компьютерных программ и операционных систем, вынужденных делать все, что в UTC время. С помощью знаков в стиле POSIX вы можете добавить время и timezone, чтобы получить время UTC. Пример: «03:30 PST8 «или» 03:30 GMT+8 «означают, что это»11:30 UTC».

И у Вас получится что Московское время GMT+3 = Etc/GMT-3.
Не спорьте! Всем добра! 😉

Пользовательские часовые пояса

Пользовательские часовые пояса в Laravel

Как работать в одном приложении со множеством часовых поясов, которые выбирают сами пользователи, но при этом в базе данных все временные метки будут храниться в едином UTC-формате, либо в часовом поясе заданном по умолчанию в приложении, что позволит нам отображать одну и ту же информацию по-разному без нарушения ее целостности.

Часовые пояса в PHP и MySQL

Заданный часовой пояс будет использоваться для PHP-функций date и datetime , и это важно, поскольку он влияет не только на вычисления даты и времени, например, на разницу между указанной датой и текущим моментом, но и на то, как метки времени будут храниться в базе данных.

Часовой пояс в PHP задается в файле php.ini , например:

[Date] date.timezone = "Europe/Moscow"

Также его можно задать на системном уровне:

date_default_timezone_set ('Europe/Moscow');

Все часовые пояса, которые поддерживает PHP, можно увидеть здесь.

В MySQL дефолтный часовой пояс задается глобально в файле /etc/mysql/my.cnf , через указание GMT-разницы ((Greenwich Mean Time, Среднее время по Гринвичу)) желаемой зоны:

[mysqld] default-time-zone = "+03:00"

Также можно задать глобальную переменную:

sudo mysql -e "SET GLOBAL time_zone = '+03:00';"

Если мы используем PDO, то можем задать часовой пояс для каждого соединения, указая GMT-разницу:

$conn->exec("SET time_zone='+03:00';");

Часовые пояса в Laravel

В Laravel по умолчанию часовой пояс установлен на UTC (Coordinated Universal Time, Всемирное координированное время), хотя можно задать другой, изменив значение timezone в config/app.php . Получить доступ к этому значению можно через config(‘app.timezone’) .

Если ваше приложение будет использоваться пользователями с разными часовыми поясами, то рекомендуется использовать UTC в качестве общесистемного часового пояса, чтобы все даты и временные метки хранились в базе данных как UTC, независимо от часового пояса пользователя (тем более, что он может измениться, например, если пользователь путешествует и зашел из другой страны), а затем конвертировать временные метки в часовой пояс пользователя, чтобы он видел их правильно.

Существуют разные подходы к решению этой проблемы, в этой статье мы попытаемся охватить различные глобальные параметры, чтобы пользователь мог задать свой часовой пояс и увидеть дату и время в соответствии со своими предпочтениями.

Поле timezone в таблице пользователей

Поскольку каждый пользователь может задать свой часовой пояс, то нам нужно дополнительное поле в таблице пользователей для хранения этой информации.

php artisan make:migration add_timezone_field_to_users_table --table=users
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class AddTimezoneFieldToUsersTable extends Migration < /** * Run the migrations. * * @return void */ public function up() < Schema::table('users', function (Blueprint $table) < $table->string('timezone', 40)->nullable(); >); > /** * Reverse the migrations. * * @return void */ public function down() < Schema::table('users', function (Blueprint $table) < $table->dropColumn('timezone'); >); > >

При этом подходе мы задаем поле как nullable , так как нет нужды хранить ненужную информацию, если пользователь использует UTC или дефолтный часовой пояс. Хранить нужно только отличающиеся часовые пояса, если пользователь их задаст.

Добавление Аксессора и Мутатора для часового пояса

После добавления timezone в $fillable[] в модели User , мы зададим аксессор и мутатор для установки и получения этого атрибута.

Поскольку, при этом подходе, поле часового пояса может быть нулевым (например, если оно равно системному часовому поясу, или если мы добавляем эту функцию в уже существующую систему, где у пользователей пока нет часового пояса), то сделаем аксессор, который, если часовой пояс пользователя пуст, выдает дефолтный часовой пояс.

В пользовательской модели зададим:

public function getTimeZoneAttribute ($value): string

Так как мы не будем хранить в базе данных часовые пояса аналогичные дефолтному, то добавим Мутатор, который, если часовой пояс, выбранный пользователем, равен дефолтному, то он не будет сохранен в базе данных.

public function setTimeZoneAttribute($value) < $this->attributes['timezone'] = $value == config('app.timezone') || is_null($value) ? null : $value; >

Хелпер Timezone

Напишем несколько хелперов, которые можно будет использовать многократно.

Существует много способов подключения хелперов, например создать app/Helpers/Helpers.php со следующей структурой:

namespace App\Helpers; use Illuminate\Support\Facades\App; class Helpers < //. >

И добавить в файл composer.json ссылку на него:

"files": [ "app/Helpers/Helpers.php" ]

Также добавим в файл config/app.php в $aliases[] ссылки на этот класс:

'aliases' => [ //.. 'Helpers' => App\Helpers\Helpers::class, ],

В Helpers.php добавим два новых хелпера для часовых поясов:

static public function getTimeZoneList() < return \Cache::rememberForever('timezones_list_collection', function () < $timestamp = time(); foreach (timezone_identifiers_list(\DateTimeZone::ALL) as $key =>$value) < date_default_timezone_set($value); $timezone[$value] = $value . ' (UTC ' . date('P', $timestamp) . ')'; >return collect($timezone)->sortKeys(); >); >

Этот метод создаст упорядоченную коллекцию с доступными часовыми поясами (используемыми в качестве ключа) вместе со смещением по Гринвичу, как показано на изображении ниже. Поскольку эта информация не будет меняться, то мы бессрочно закэшируем её.

выбор часового пояса в выпадающем меню

Мы можем заменить этот метод упрощенной версией и использовать встроенную PHP-функцию timezone_identifiers_list() , которая вернет массив со всеми поддерживаемыми часовыми поясами.

Также добавим метод getUserTimeZone() , который попытается получить часовой пояс, заданный пользователем, если таковой существует, а в противном случае он вернет дефолтный часовой пояс.

Здесь мы будем использовать Laravel-хелпер optional() , чтобы избежать ошибок, если пользователь не залогинен.

static public function getUserTimeZone() < return optional(auth()->user())->timezone ?? config('app.timezone'); >

Выбор часового пояса пользователем

Используя ранее созданный хелпер, добавим форму, в которой пользователь может задавать свой часовой пояс. Например:

 

В Laravel есть правило проверки timezone , поэтому мы можем легко валидировать введенное значение:

'timezone' => ['required', 'timezone']

Получение часового пояса пользователя

Если мы хотим предварительно задать часовой пояс пользователя в форме или добавить его в скрытом поле в процессе регистрации, то можно получить текущий часовой пояс пользователя из js-библиотеки moment .

Для этого нам нужны библиотеки moment и moment-timezone . Будем использовать метод moment.tz.guess() :

   

Либо можно получить эту информацию и без использования внешних библиотек, но такой код может не заработать на старых браузерах:

Intl.DateTimeFormat().resolvedOptions().timeZone;

Использование часового пояса пользователя в контроллерах и blade-шаблонах

Существуют различные варианты преобразования дат и временных меток с использованием часового пояса пользователя.

Если раздел требует, чтобы пользователь был авторизован, то мы можем использовать, например:

timezone ) >>

Или хелпер, чтобы учесть неавторизованные случаи и возвращать дефолтный часовой пояс:

Чтобы отпарсить временную метку с использованием часового пояса пользователя:

Carbon::parse( $model->timestamp_field )->setTimezone( Helpers::getUserTimeZone() );

Сохранение временных меток в базе данных в формате UTC

Обычно пользователь добавляет временные метки, выбирая дату и время из javascript-библиотеки, используя свой собственный часовой пояс, поэтому мы должны преобразовать эту дату в UTC, чтобы сохранить ее в нашей базе данных.

Предположим, что пользователь может добавлять элементы и задавать их дату создания, а часовой пояс отличается от дефолтного часового пояса. Один из способов преобразования такой даты перед сохранением:

$request->merge([ 'created_at' => Carbon::parse( $request->input('created_at'), Helpers::getUserTimeZone() ) ->setTimeZone( config('app.timezone') ) ->format( 'Y-m-d H:i:s' ), ]);

Таким образом, мы указываем парсеру, что часовой пояс данной временной метки имеет тип, и что мы преобразуем его в UTC или дефолтный часовой пояс нашего приложения.

Важно, чтобы это преобразование выполнялось после валидации, поскольку в противном случае, если проверка не удалась, то при вызове old() в шаблоне, пользователь увидит дату в формате UTC, а не в своем часовом поясе.

Пользователь имеет возможность редактировать этот элемент, поэтому сделаем, чтобы он отображался в его часовом поясе — преобразуем его перед отправкой в ​​шаблон:

$model->created_at = Carbon::parse( $model->created_at )->setTimezone( Helpers::getUserTimeZone() );

Аксессоры часового пояса пользовательской модели

Если мы хотим, чтобы временные метки времени по умолчанию возвращались в часовом поясе пользователя (или дефолтном, если пользователь не залогинен или не установил свой часовой пояс), то можна задать аксессоры в модели.

public function getCreatedAtAttribute($value): Carbon < return Carbon::parse($value)->timezone(Helpers::getUserTimeZone()); > public function getUpdatedAtAttribute($value): Carbon < return Carbon::parse($value)->timezone(Helpers::getUserTimeZone()); >

Blade-компонент для дат с часовым поясом пользователя

Чтобы упростить преобразование временных меток с часовым поясом пользователя в Blade, мы можем создать отдельный компонент.

php artisan make:component DateTimeZone --inline

Используем —inline , чтобы избежать создания шаблона, поскольку для упрощения этого компонента в нём нет необходимости. Преобразованная дата будет возвращена непосредственно из метода render() класса app/View/Components/DateTimeZone.php .

Код этого файла:

namespace App\View\Components; use App\Helpers\Helpers; use Carbon\Carbon; use Illuminate\View\Component; class DateTimeZone extends Component < public Carbon $date; public mixed $format; /** * Create a new component instance. * * @return void */ public function __construct(Carbon $date, $format = null) < $this->date = $date->setTimezone(Helpers::getUserTimeZone()); $this->format = $format; > protected function format() < return $this->format ?? 'Y-m-d H:i:s'; > /** * Get the view / contents that represent the component. * * @return \Illuminate\Contracts\View\View|\Closure|string */ public function render() < return $this->date->format($this->format()); > >

$format задан как mixed , поскольку может иметь тип как string так и null , если отсутствует. Снова будем использовать хелпер getUserTimeZone() , чтобы получить, либо часовой пояс, заданный пользователем, либо дефолтный.

В Blade можем использовать этот компонент, передавая ему временную метку для преобразования и, необязательно, указывая выходной формат, который по умолчанию будет, если этот параметр не указан, Y md H: i: s .

created_at" /> created_at" format="d-m-Y H:i:s" /> created_at" format="d/m/YH:i" />

Нерекомендуемый подход

Некоторые, при работе с несколькими часовыми поясами в Laravel, создают мидлвар, в котором дефолтный часовой пояс задается на основе часового пояса пользователя с помощью команды date_default_timezone_set() .

Этого делать не рекомендуется, поскольку таким образом часовой пояс всей системы изменяется для каждого пользователя и в базе данных будут сохраняться временные метки с разными часовыми поясами.

Наш Телеграм-канал — следите за новостями о Laravel.

Задать вопросы по урокам можно на нашем форуме.

Yii Framework

совершенно случайно наткнулся на следующее — в таблицах выводится время с неправильным таймзон, несмотря на то что в системе, в бд, в пхп все прописано, и все работает, а в yii2 нет.

система centos7, php 5.6, postgresql9.4, yii2.0.3
везде установлена Europe/Moscow, сервисы перегружены для применения настроек

$date
Mon Mar 30 23:47:54 MSK 2015
$php -r ‘echo date(«Y-m-d H:i:s T»);’
2015-03-30 23:49:24 MSK
в код вставляю — тоже самое
2015-03-30 23:52:44 MSK

в конфиге Yii пробывал и внутренний и php

'formatter' => [ 'timeZone' => 'Europe/Moscow', 'dateFormat' => 'd.MM.Y', 'timeFormat' => 'H:mm:ss', //'datetimeFormat' => 'd.MM.Y HH:mm', 'datetimeFormat' => 'php:Y-m-d H:i:s', ], 

в бд, в ячейке:
2015-03-30 23:42:49.420899+03
а в таблице выводит
2015-03-31 00:42:49

откуда такое может быть ?
yii имеет свои файлы таймзон ?

upd
указал в конфиге

'datetimeFormat' => 'php:Y-m-d H:i:s T O',

2015-03-31 00:42:49 GMT+04:00
а если убрать форматирование, то выдает в таблице как и должно быть
2015-03-30 23:42:49.420899+03
yiijeka Сообщения: 3103 Зарегистрирован: 2012.01.28, 09:14 Откуда: Беларусь Контактная информация:

Re: Time zone — Europe/Moscow

Сообщение yiijeka » 2015.03.31, 08:09

в GridView по умолчанию используется Intl форматирование, для него нужно тоже указать:

'formatter' => [ 'defaultTimeZone' => 'Europe/Minsk' ], 

‘dateFormat’ и прочие форматы лучше оставить без изменений, обычно в нужном, принятом формате всё показывается само.

В таблице можно явно указать формат:

[ 'attribute'=>'value1', 'format'=>['date', 'short'] // или вместо short в формате php:d.m.Y ,что равнозначно ] 

sm-vasya Сообщения: 191 Зарегистрирован: 2015.03.04, 01:12

Re: Time zone — Europe/Moscow

Сообщение sm-vasya » 2015.03.31, 13:03

yiijeka писал(а): в GridView по умолчанию используется Intl форматирование, для него нужно тоже указать:

'formatter' => [ 'defaultTimeZone' => 'Europe/Minsk' ],

‘dateFormat’ и прочие форматы лучше оставить без изменений, обычно в нужном, принятом формате всё показывается само.

а не подскажете более точнее куда вписать это ? если в конфиг, в ‘components’ => ‘formatter’ то уже вписал

yiijeka писал(а): В таблице можно явно указать формат:

[ 'attribute'=>'value1', 'format'=>['date', 'short'] // или вместо short в формате php:d.m.Y ,что равнозначно ]

да дело собственно не в формате, а в том что часы в другом часовом поясе

mickgeek Сообщения: 957 Зарегистрирован: 2014.05.31, 20:50 Откуда: Санкт-Петербург Контактная информация:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *