пятница, 31 июля 2020 г.

Пакет time в Golang, тип Time, методы Date, Clock, Day

Метод Date

func (t Time) Date() (year int, month Month, day int)

Date возвращает год, месяц и день, в который происходит t.

Пример использования Date

package main

import (
    "fmt"
    "time"
)

func main() {
    d := time.Date(2000, 2, 1, 12, 30, 0, 0, time.UTC)
    year, month, day := d.Date()

    fmt.Printf("year = %v\n", year)
    fmt.Printf("month = %v\n", month)
    fmt.Printf("day = %v\n", day)

}

Вывод:

year = 2000
month = February
day = 1

Метод Clock

func (t Time) Clock() (hour, min, sec int)

Clock возвращают часы, минуты и секунды в течение дня, указанного в t.

Пример использования Clock

package main

import (
    "fmt"
    "time"
)

func main() {
    d := time.Now()
    hour, min, sec := d.Clock()

    fmt.Printf("hour = %v\n", hour)
    fmt.Printf("min = %v\n", min)
    fmt.Printf("sec = %v\n", sec)

}

Вывод:

hour = 19
min = 22
sec = 27

Метод Day

func (t Time) Day() int

Day возвращает день месяца, указанного в t.

Пример использования Day

package main

import (
    "fmt"
    "time"
)

func main() {
    d := time.Date(2000, 2, 1, 12, 30, 0, 0, time.UTC)
    day := d.Day()

    fmt.Printf("day = %v\n", day)

}

Вывод:

day = 1


Читайте также:


четверг, 30 июля 2020 г.

Пакет time в Golang, тип Time, методы After, Before, Equal, IsZero

Метод After

func (t Time) After(u Time) bool

After сообщает, является ли момент времени t после u.

Пример использования After

package main

import (
    "fmt"
    "time"
)

func main() {
    year2000 := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
    year3000 := time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC)

    isYear3000AfterYear2000 := year3000.After(year2000) // True
    isYear2000AfterYear3000 := year2000.After(year3000) // False

    fmt.Printf("year3000.After(year2000) = %v\n", isYear3000AfterYear2000)
    fmt.Printf("year2000.After(year3000) = %v\n", isYear2000AfterYear3000)

}

Вывод:

year3000.After(year2000) = true
year2000.After(year3000) = false

Метод Before

func (t Time) Before(u Time) bool

Before сообщает, находится ли момент времени t перед u.

Пример использования Before

package main

import (
    "fmt"
    "time"
)

func main() {
    year2000 := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
    year3000 := time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC)

    isYear2000BeforeYear3000 := year2000.Before(year3000) // True
    isYear3000BeforeYear2000 := year3000.Before(year2000) // False

    fmt.Printf("year2000.Before(year3000) = %v\n", isYear2000BeforeYear3000)
    fmt.Printf("year3000.Before(year2000) = %v\n", isYear3000BeforeYear2000)

}

Вывод:

year2000.Before(year3000) = true
year3000.Before(year2000) = false

Метод Equal

func (t Time) Equal(u Time) bool

Equal сообщает, представляют ли t и u один и тот же момент времени. Два времени могут быть равны, даже если они находятся в разных местах. Например, 6:00 +0200 and 4:00 UTC равны. О ловушках использования == со значениями Time; большая часть кода должна использовать вместо этого Equal.

Пример использования Equal

package main

import (
    "fmt"
    "time"
)

func main() {
    secondsEastOfUTC := int((8 * time.Hour).Seconds())
    beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)

    // В отличие от оператора равенства (==), Equal знает, 
    // что d1 и d2 являются одним и тем же моментом, 
    // но в разных часовых поясах.
    d1 := time.Date(2000, 2, 1, 12, 30, 0, 0, time.UTC)
    d2 := time.Date(2000, 2, 1, 20, 30, 0, 0, beijing)

    datesEqualUsingEqualOperator := d1 == d2
    datesEqualUsingFunction := d1.Equal(d2)

    fmt.Printf("datesEqualUsingEqualOperator = %v\n", datesEqualUsingEqualOperator)
    fmt.Printf("datesEqualUsingFunction = %v\n", datesEqualUsingFunction)

}

Вывод:

datesEqualUsingEqualOperator = false
datesEqualUsingFunction = true

Метод IsZero

func (t Time) IsZero() bool

IsZero сообщает, представляет ли t нулевой момент времени, January 1, year 1, 00:00:00 UTC.

Пример использования IsZero

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Date(1, time.January, 1, 00, 0, 0, 0, time.UTC)
    fmt.Printf("Это нулевое значение Time %s\n", t.UTC())
    fmt.Printf("Верно? %v\n", t.IsZero())
}

Вывод:

Это нулевое значение Time 0001-01-01 00:00:00 +0000 UTC
Верно? true


Читайте также:


среда, 29 июля 2020 г.

Пакет time в Golang, тип Time, методы Add, AddDate

Метод Add

func (t Time) Add(d Duration) Time

Add возвращает время t+d.

Пример использования Add

package main

import (
    "fmt"
    "time"
)

func main() {
    start := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC)
    afterTenSeconds := start.Add(time.Second * 10)
    afterTenMinutes := start.Add(time.Minute * 10)
    afterTenHours := start.Add(time.Hour * 10)
    afterTenDays := start.Add(time.Hour * 24 * 10)

    fmt.Printf("start = %v\n", start)
    fmt.Printf("start.Add(time.Second * 10) = %v\n", afterTenSeconds)
    fmt.Printf("start.Add(time.Minute * 10) = %v\n", afterTenMinutes)
    fmt.Printf("start.Add(time.Hour * 10) = %v\n", afterTenHours)
    fmt.Printf("start.Add(time.Hour * 24 * 10) = %v\n", afterTenDays)

}

Вывод:

start = 2009-01-01 12:00:00 +0000 UTC
start.Add(time.Second * 10) = 2009-01-01 12:00:10 +0000 UTC
start.Add(time.Minute * 10) = 2009-01-01 12:10:00 +0000 UTC
start.Add(time.Hour * 10) = 2009-01-01 22:00:00 +0000 UTC
start.Add(time.Hour * 24 * 10) = 2009-01-11 12:00:00 +0000 UTC

Метод AddDate

func (t Time) AddDate(years int, months int, days int) Time

AddDate возвращает время, соответствующее добавлению заданного количества лет, месяцев и дней к t. Например, AddDate(-1, 2, 3), примененный к January 1, 2011, возвращает March 4, 2010.

AddDate нормализует свой результат так же, как Date, например, добавление одного месяца к October 31 приводит к December 1, нормализованной форме для November 31.

Пример использования AddDate

package main

import (
    "fmt"
    "time"
)

func main() {
    start := time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC)
    oneDayLater := start.AddDate(0, 0, 1)
    oneMonthLater := start.AddDate(0, 1, 0)
    oneYearLater := start.AddDate(1, 0, 0)

    fmt.Printf("oneDayLater: start.AddDate(0, 0, 1) = %v\n", oneDayLater)
    fmt.Printf("oneMonthLater: start.AddDate(0, 1, 0) = %v\n", oneMonthLater)
    fmt.Printf("oneYearLater: start.AddDate(1, 0, 0) = %v\n", oneYearLater)

}

Вывод:

oneDayLater: start.AddDate(0, 0, 1) = 2009-01-02 00:00:00 +0000 UTC
oneMonthLater: start.AddDate(0, 1, 0) = 2009-02-01 00:00:00 +0000 UTC
oneYearLater: start.AddDate(1, 0, 0) = 2010-01-01 00:00:00 +0000 UTC


Читайте также:


Пакет time в Golang, функции Parse, ParseInLocation

Функция Parse

func Parse(layout, value string) (Time, error)

Parse разбирает отформатированную строку и возвращает значение времени, которое она представляет. layout определяет формат, показывая, как эталонное время, определенное как

Mon Jan 2 15:04:05 -0700 MST 2006

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

Предопределенные макеты ANSIC, UnixDate, RFC3339 и другие описывают стандартные и удобные представления эталонного времени.

Элементы, опущенные в value, предполагаются равными нулю или, если ноль невозможен, равны единице, поэтому анализ "3:04pm" возвращает время, соответствующее Jan 1, year 0, 15:04:00 UTC (обратите внимание, что, поскольку год 0, это время до нулевого Time). Годы должны быть в диапазоне 0000..9999. День недели проверяется на синтаксис, но в противном случае он игнорируется.

Для макетов с указанием двузначного года 06 значение NN >= 69 будет рассматриваться как 19NN, а значение NN < 69 будет рассматриваться как 20NN.

При отсутствии индикатора часового пояса Parse возвращает время в UTC.

При анализе времени со смещением зоны, например -0700, если смещение соответствует часовому поясу, используемому текущим местоположением (Local), то Parse использует это местоположение и зону в возвращенном времени. В противном случае он записывает время, как находящееся в сфабрикованном месте, со временем, зафиксированным в заданном смещении зоны.

При разборе времени с аббревиатурой зоны, такой как MST, если аббревиатура зоны имеет определенное смещение в текущем местоположении, то это смещение используется. Аббревиатура зоны "UTC" распознается как UTC независимо от местоположения. Если аббревиатура зоны неизвестна, Parse записывает время, как находящееся в сфабрикованном месте с данной аббревиатурой зоны и нулевым смещением. Этот выбор означает, что такое время может быть проанализировано и переформатировано с той же компоновкой без потерь, но точный момент, используемый в представлении, будет отличаться фактическим смещением зоны. Чтобы избежать таких проблем, предпочитайте временные макеты, которые используют числовое смещение зоны, или используйте ParseInLocation.

Пример использования Parse

package main

import (
    "fmt"
    "time"
)

func main() {
    // longForm показывает в качестве примера, 
    // как эталонное время 
    // будет представлено в желаемом макете.
    const longForm = "Jan 2, 2006 at 3:04pm (MST)"
    t, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)")
    fmt.Println(t)

    // shortForm это другой способ 
    // как будет представлено эталонное время
    // в нужном макете; нет часового пояса.
    // Примечание: без явной зоны возвращает время в UTC.
    const shortForm = "2006-Jan-02"
    t, _ = time.Parse(shortForm, "2013-Feb-03")
    fmt.Println(t)

    // Некоторые допустимые макеты являются 
    // недопустимыми значениями времени 
    // из-за спецификаторов формата
    // например _ для пробела и Z для информации о зоне.
    // Например, макет RFC3339 2006-01-02T15:04:05Z07:00
    // содержит как Z, так и смещение часового пояса 
    // для обработки обеих допустимых опций:
    // 2006-01-02T15:04:05Z
    // 2006-01-02T15:04:05+07:00
    t, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
    fmt.Println(t)
    t, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05+07:00")
    fmt.Println(t)
    _, err := time.Parse(time.RFC3339, time.RFC3339)
    fmt.Println("error", err) 
    // Возвращает ошибку, 
    // поскольку макет не является допустимым значением
    
}

Вывод:

2013-02-03 19:54:00 +0000 PST
2013-02-03 00:00:00 +0000 UTC
2006-01-02 15:04:05 +0000 UTC
2006-01-02 15:04:05 +0700 +0700
error parsing time "2006-01-02T15:04:05Z07:00": extra text: 07:00

Функция ParseInLocation

func ParseInLocation(layout, value string, loc *Location) (Time, error)

ParseInLocation похож на Parse, но отличается двумя важными способами. Во-первых, при отсутствии информации о часовом поясе Parse интерпретирует время как UTC; ParseInLocation интерпретирует время как в переданном местоположении. Во-вторых, когда задано смещение или сокращение зоны, Parse пытается сопоставить его с Local местоположением; ParseInLocation использует переданное местоположение.

Пример использования ParseInLocation

package main

import (
    "fmt"
    "time"
)

func main() {
    loc, _ := time.LoadLocation("Europe/Berlin")

    // Будет искать имя CEST в часовом поясе Europe/Berlin.
    const longForm = "Jan 2, 2006 at 3:04pm (MST)"
    t, _ := time.ParseInLocation(longForm, "Jul 9, 2012 at 5:02am (CEST)", loc)
    fmt.Println(t)

    // Примечание: 
    // без явной зоны возвращает время в указанном location.
    const shortForm = "2006-Jan-02"
    t, _ = time.ParseInLocation(shortForm, "2012-Jul-09", loc)
    fmt.Println(t)

}

Вывод:

2012-07-09 05:02:00 +0200 CEST
2012-07-09 00:00:00 +0200 CEST


Читайте также:


вторник, 28 июля 2020 г.

Пакет time в Golang, функции Date, Now, Unix

Функция Date

func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time

Date возвращает Time, соответствующее

yyyy-mm-dd hh:mm:ss + nsec nanoseconds

в соответствующей зоне для этого времени в данном месте.

Значения month, day, hour, min, sec, и nsec могут выходить за пределы своих обычных диапазонов и будут нормализованы во время преобразования. Например, October 32 конвертируется в November 1.

Переход на летнее время пропускает или повторяет время. Например, в Соединенных Штатах 13 марта 2011 г. 2:15 никогда не происходило, а 6 ноября 2011 г. 1:15 происходило дважды. В таких случаях выбор часового пояса и, следовательно, времени не является четко определенным. Date возвращает время, которое является правильным в одной из двух зон, участвующих в переходе, но не гарантирует, в какой именно.

Date паникует, если loc - nil.

Пример использования Date

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
    fmt.Printf("Go запущен %s\n", t.Local())
}

Вывод

Go запущен 2009-11-10 23:00:00 +0000 UTC

Функция Now

func Now() Time

Now возвращает текущее местное время.

Пример использования Now

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Now()
    fmt.Printf("Сейчас %s\n", t)
}

Вывод

Сейчас 2020-07-28 09:27:51.223683882 +0500 +05 m=+0.000052967

Функция Unix

func Unix(sec int64, nsec int64) Time

Unix возвращает местное время, соответствующее указанному времени Unix, sec секунд и nsec наносекунд, с 1 января 1970 года UTC. Допустимо передавать nsec вне диапазона [0, 999999999]. Не все значения sec имеют соответствующее значение времени. Одним из таких значений является 1<<63-1 (наибольшее значение int64).

Пример использования Unix

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Now().Unix()
    fmt.Printf("Текущий timestamp %d\n", t)
}

Вывод

Текущий timestamp 1596910715


Читайте также:


Пакет time в Golang, тип Time

type Time struct {
    // содержит отфильтрованные или неэкспортированные поля
}

Time представляет собой момент времени с наносекундной точностью.

Программы, использующие времена, обычно должны хранить и передавать их как значения, а не как указатели. То есть переменные времени и поля структуры должны иметь тип time.Time, а не *time.Time.

Значение Time может использоваться несколькими программами одновременно, за исключением того, что методы GobDecode, UnmarshalBinary, UnmarshalJSON и UnmarshalText не являются безопасными для конкурентности.

Моменты Time можно сравнить с помощью методов Before, After и Equal. Метод Sub вычитает два момента, создавая Duration. Метод Add добавляет Time и Duration, создавая Time.

Нулевым значением типа Time является January 1, year 1, 00:00:00.000000000 UTC. Поскольку это время вряд ли подходит на практике, метод IsZero предоставляет простой способ обнаружения времени, которое не было явно инициализировано.

Каждое время связывает с ним Location (местоположение), к которому обращаются при расчете формы представления времени, таких методах как Format, Hour и Year. Методы Local, UTC и In возвращают Time с определенным местоположением. Изменение местоположения таким образом изменяет только представление; оно не меняет момент времени, который будет обозначен, и, следовательно, не влияет на вычисления со временем.

Представления значения Time, сохраненного методами GobEncode, MarshalBinary, MarshalJSON и MarshalText, хранят смещение Time.Location, но не имя местоположения. Поэтому они теряют информацию о переходе на летнее время.

В дополнение к требуемым показаниям "настенных часов", Time может содержать дополнительное показание монотонных часов текущего процесса, чтобы обеспечить дополнительную точность для сравнения или вычитания.

Обратите внимание, что оператор Go == сравнивает не только момент времени, но и местоположение и показания монотонных часов. Следовательно, значения времени не должны использоваться в качестве ключей карты или базы данных без предварительной гарантии того, что для всех значений было установлено одинаковое местоположение, что может быть достигнуто с помощью метода UTC или Local, и что монотонное считывание часов было удалено установкой t = t.Round(0). В общем, предпочитайте t.Equal(u), а не t == u, так как t.Equal использует наиболее точное из доступных сравнений и правильно обрабатывает случай, когда только один из его аргументов имеет монотонное чтение часов.


Читайте также:


воскресенье, 26 июля 2020 г.

Пакет time в Golang, тип Ticker

Ticker содержит канал, который поставляет "тики" часов с интервалами.

type Ticker struct {
    C <-chan Time // Канал, по которому доставляются тики.
    // содержит отфильтрованные или неэкспортированные поля
}

Функция NewTicker

func NewTicker(d Duration) *Ticker

NewTicker возвращает новый Ticker, содержащий канал, который будет отправлять время с периодом, заданным аргументом продолжительности. Он корректирует интервалы или сбрасывает тики, чтобы восполнить медленные приемники. Продолжительность d должна быть больше нуля; если нет, NewTicker будет паниковать. Остановите тикер, чтобы освободить связанные ресурсы.

Пример использования Ticker

package main

import (
    "fmt"
    "time"
)

func main() {
    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()
    done := make(chan bool)
    go func() {
        time.Sleep(10 * time.Second)
        done <- true
    }()
    for {
        select {
        case <-done:
            fmt.Println("Готово!")
            return
        case t := <-ticker.C:
            fmt.Println("Текущее время: ", t)
        }
    }
}

Вывод:

Текущее время:  2020-07-26 22:03:37.925067 +0500 +05 m=+1.008175801
Текущее время:  2020-07-26 22:03:38.9258884 +0500 +05 m=+2.008997201
Текущее время:  2020-07-26 22:03:39.9282 +0500 +05 m=+3.011308801
Текущее время:  2020-07-26 22:03:40.9290208 +0500 +05 m=+4.012129601
Текущее время:  2020-07-26 22:03:41.9298391 +0500 +05 m=+5.012947901
Текущее время:  2020-07-26 22:03:42.9313325 +0500 +05 m=+6.014441301
Текущее время:  2020-07-26 22:03:43.9330786 +0500 +05 m=+7.016187401
Текущее время:  2020-07-26 22:03:44.9390601 +0500 +05 m=+8.022168901
Текущее время:  2020-07-26 22:03:45.9320627 +0500 +05 m=+9.015171501
Текущее время:  2020-07-26 22:03:46.941485 +0500 +05 m=+10.024593801
Готово!

Метод Stop

func (t *Ticker) Stop()

Stop отключает тикер. После остановки никакие тики больше не будут отправляться. Stop не закрывает канал, чтобы предотвратить чтение из канала конкурентной goroutine ошибочного "тика".


Читайте также:


Пакет time в Golang, тип Month

Month указывает месяц года (January = 1, February = 2, March = 3, ...).

type Month int

const (
    January Month = 1 + iota
    February
    March
    April
    May
    June
    July
    August
    September
    October
    November
    December
)

Пример использования Month:

package main

import (
    "fmt"
    "time"
)

func main() {
    _, month, day := time.Now().Date()
    if month == time.November && day == 10 {
        fmt.Println("День рождения Go!")
    }   
    fmt.Println("Текущий месяц:", month)    
    fmt.Println("Текущий день:", day )
}

Вывод:

День рождения Go!
Текущий месяц: November
Текущий день: 10

Метод String

func (m Month) String() string

String возвращает английское название месяца ("January", "February", ...).


Читайте также:


суббота, 25 июля 2020 г.

Пакет time в Golang, функции возвращающие Location

Функция FixedZone

func FixedZone(name string, offset int) *Location

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

Пример использования FixedZone:

package main

import (
    "fmt"
    "time"
)

func main() {
    loc := time.FixedZone("UTC-8", -8*60*60)
    t := time.Date(2009, time.November, 10, 23, 0, 0, 0, 
                   loc)
    fmt.Println("Время:", t.Format(time.RFC822))
}

Вывод:

Время: 10 Nov 09 23:00 UTC-8

Функция LoadLocation

func LoadLocation(name string) (*Location, error)

LoadLocation возвращает Location с заданным именем.

Если имя "" или "UTC", LoadLocation возвращает UTC. Если имя "Local", LoadLocation возвращает Local.

В противном случае имя считается именем местоположения, соответствующим файлу в базе данных часового пояса IANA, например "America/New_York".

База данных часовых поясов, необходимая для LoadLocation, может присутствовать не во всех системах, особенно в не-Unix системах. LoadLocation просматривает каталог или несжатый zip-файл с именем переменной среды ZONEINFO, если таковой имеется, затем просматривает известные места установки в системах Unix и, наконец, просматривает файл $GOROOT/lib/time/zoneinfo.zip.

Пример использования LoadLocation:

package main

import (
    "fmt"
    "time"
)

func main() {
    location, err := time.LoadLocation("America/Los_Angeles")
    if err != nil {
        panic(err)
    }

    timeInUTC := time.Date(2018, 8, 30, 12, 0, 0, 0, 
                           time.UTC)
    fmt.Println(timeInUTC)
    fmt.Println(timeInUTC.In(location))
}

Вывод:

2018-08-30 12:00:00 +0000 UTC
2018-08-30 05:00:00 -0700 PDT


Читайте также:


Пакет time в Golang, тип Location

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

type Location struct {
    // содержит отфильтрованные или неэкспортированные поля
}

Local представляет местный часовой пояс системы. В системах Unix Local обращается к переменной окружения TZ, чтобы найти часовой пояс для использования. Отсутствие TZ означает использование системного значения по умолчанию /etc/localtime. TZ="" означает использовать UTC. TZ="foo" означает использовать файл foo в системном каталоге часовых поясов.

var Local *Location = &localLoc

UTC представляет собой всемирное координированное время (UTC, Universal Coordinated Time).

var UTC *Location = &utcLoc

Пример использования Location

package main

import (
    "fmt"
    "time"
)

func main() {
    // В Китае нет летнего времени. 
    // Китай использует 
    // фиксированное 8-часовое смещение от UTC.
    secondsEastOfUTC := int((8 * time.Hour).Seconds())
    beijing := time.FixedZone("Beijing Time", 
                              secondsEastOfUTC)

    // Если в системе есть база данных часовых поясов, 
    // можно загрузить местоположение из нее, например:
    // newYork, err := time.LoadLocation("America/New_York")

    // Создание времени требует местоположения (location). 
    // Распространенными местоположениями 
    // являются time.Local и time.UTC.
    timeInUTC := time.Date(2009, 1, 1, 12, 0, 0, 0, 
                           time.UTC)
    sameTimeInBeijing := time.Date(2009, 1, 1, 20, 0, 0, 0, 
                                   beijing)

    // Хотя время по UTC составляет 1200, 
    // а время по Пекину - 2000, 
    // Пекин на 8 часов вперед, 
    // поэтому две даты фактически представляют 
    // один и тот же момент.
    timesAreEqual := timeInUTC.Equal(sameTimeInBeijing)
    fmt.Println(timesAreEqual) 
    // печатает true
}


Читайте также:


пятница, 24 июля 2020 г.

Пакет time в Golang, методы типа Duration

Метод Hours

func (d Duration) Hours() float64

Hours возвращает продолжительность в виде количества часов числом с плавающей запятой.

Пример использования Hours

package main

import (
    "fmt"
    "time"
)

func main() {
    h, _ := time.ParseDuration("4h30m")
    fmt.Printf("Осталось %.1f часа до полудня.", h.Hours())
}

Вывод:

Осталось 4.5 часа до полудня.

Метод Microseconds

func (d Duration) Microseconds() int64

Microseconds возвращает длительность в виде целого числа микросекунд.

Пример использования Microseconds

package main

import (
    "fmt"
    "time"
)

func main() {
    u, _ := time.ParseDuration("1s")
    fmt.Printf("Одна секунда это %d микросекунд.\n", 
               u.Microseconds())
}

Вывод:

Одна секунда это 1000000 микросекунд.

Метод Milliseconds

func (d Duration) Milliseconds() int64

Milliseconds возвращает длительность в виде целого числа миллисекунд.

Пример использования Milliseconds

package main

import (
    "fmt"
    "time"
)

func main() {
    u, _ := time.ParseDuration("1s")
    fmt.Printf("Одна секунда это %d миллисекунд.\n", 
               u.Microseconds())
}

Вывод:

Одна секунда это 1000 миллисекунд.

Методы Minutes

func (d Duration) Minutes() float64

Minutes возвращает продолжительность в виде количества минут числом с плавающей точкой.

Пример использования Minutes

package main

import (
    "fmt"
    "time"
)

func main() {
    m, _ := time.ParseDuration("1h30m")
    fmt.Printf("Фильм длится %.0f минут.", m.Minutes())
}

Вывод:

Фильм длится 90 минут.

Метод Nanoseconds

func (d Duration) Nanoseconds() int64

Nanoseconds возвращает длительность в виде целого числа наносекунд.

Пример использования Nanoseconds

package main

import (
    "fmt"
    "time"
)

func main() {
    u, _ := time.ParseDuration("1µs")
    fmt.Printf("Одна микросекунда это %d наносекунд.\n", 
               u.Nanoseconds())
}

Вывод:

Одна микросекунда это 1000 наносекунд.

Метод Round (с версии Go 1.9)

func (d Duration) Round(m Duration) Duration

Round возвращает результат округления d до ближайшего кратного m. Поведение при округлении для значений на полпути заключается в округлении от нуля. Если результат превышает максимальное (или минимальное) значение, которое может быть сохранено в Duration, Round возвращает максимальную (или минимальную) продолжительность. Если m <= 0, Round возвращает d без изменений.

Пример использования Round

package main

import (
    "fmt"
    "time"
)

func main() {
    d, err := time.ParseDuration("1h15m30.918273645s")
    if err != nil {
        panic(err)
    }

    round := []time.Duration{
        time.Nanosecond,
        time.Microsecond,
        time.Millisecond,
        time.Second,
        2 * time.Second,
        time.Minute,
        10 * time.Minute,
        time.Hour,
    }

    for _, r := range round {
        fmt.Printf("d.Round(%6s) = %s\n", 
                   r, d.Round(r).String())
    }
}

Вывод:

d.Round(   1ns) = 1h15m30.918273645s
d.Round(   1µs) = 1h15m30.918274s
d.Round(   1ms) = 1h15m30.918s
d.Round(    1s) = 1h15m31s
d.Round(    2s) = 1h15m30s
d.Round(  1m0s) = 1h16m0s
d.Round( 10m0s) = 1h20m0s
d.Round(1h0m0s) = 1h0m0s

Метод Seconds

func (d Duration) Seconds() float64

Seconds возвращает продолжительность в виде количества секунд числом с плавающей запятой.

Пример использования Seconds

package main

import (
    "fmt"
    "time"
)

func main() {
    m, _ := time.ParseDuration("1m30s")
    fmt.Printf("Полторы минуты это %.0f секунд.", 
               m.Seconds())
}

Вывод:

Полторы минуты это 90 секунд.

Метод String

func (d Duration) String() string

String возвращает строку, представляющую продолжительность в форме "72h3m0.5s". Ведущие нулевые элементы опущены. В качестве особого случая для форматов длительностью менее одной секунды используется меньшая единица измерения (милли-, микро- или наносекунды), чтобы гарантировать, что начальная цифра не равна нулю. Нулевая длительность форматируется как 0s.

Пример использования String

package main

import (
    "fmt"
    "time"
)

func main() {
    t1 := time.Date(2016, time.August, 15, 0, 0, 0, 0, time.UTC)
    t2 := time.Date(2017, time.February, 16, 0, 0, 0, 0, time.UTC)
    fmt.Println(t2.Sub(t1).String())
}

Вывод:

4440h0m0s

Метод Truncate (с версии Go 1.9)

func (d Duration) Truncate(m Duration) Duration

Truncate возвращает результат округления d до нуля, кратный m. Если m <= 0, Truncate возвращает d без изменений.

Пример использования Truncate

package main

import (
    "fmt"
    "time"
)

func main() {
    d, err := time.ParseDuration("1h15m30.918273645s")
    if err != nil {
        panic(err)
    }

    trunc := []time.Duration{
        time.Nanosecond,
        time.Microsecond,
        time.Millisecond,
        time.Second,
        2 * time.Second,
        time.Minute,
        10 * time.Minute,
        time.Hour,
    }

    for _, t := range trunc {
        fmt.Printf("d.Truncate(%6s) = %s\n", 
                   t, d.Truncate(t).String())
    }
}

Вывод:

d.Truncate(   1ns) = 1h15m30.918273645s
d.Truncate(   1µs) = 1h15m30.918273s
d.Truncate(   1ms) = 1h15m30.918s
d.Truncate(    1s) = 1h15m30s
d.Truncate(    2s) = 1h15m30s
d.Truncate(  1m0s) = 1h15m0s
d.Truncate( 10m0s) = 1h10m0s
d.Truncate(1h0m0s) = 1h0m0s


Читайте также:


Пакет time в Golang, тип Duration и функции работающие с ним

type Duration int64

Duration представляет прошедшее время между двумя моментами в виде подсчета int64 наносекунд. Представление ограничивает наибольшую представляемую продолжительность приблизительно 290 годами.

package main

import (
    "fmt"
    "time"
)

func expensiveCall() {
    time.Sleep(3 * time.Second)
}

func main() {
    t0 := time.Now()
    expensiveCall()
    t1 := time.Now()
    fmt.Printf("Вызов занимает %v для выполнения.\n", 
               t1.Sub(t0))
}

Вывод:

Вызов занимает 3.000154165s для выполнения.

Функция ParseDuration

func ParseDuration(s string) (Duration, error)

ParseDuration анализирует строку продолжительности. Строка продолжительности - это, возможно, последовательность десятичных чисел со знаком, каждое из которых содержит необязательную дробь и суффикс единицы, например "300ms", "-1.5h" или "2h45m". Допустимые единицы времени: "ns", "us" (или "µs"), "ms", "s", "m", "h".

Пример использования ParseDuration

package main

import (
    "fmt"
    "time"
)

func main() {
    hours, _ := time.ParseDuration("10h")
    complex, _ := time.ParseDuration("1h10m10s")
    micro, _ := time.ParseDuration("1µs")
    // Функция также принимает некорректный, 
    // но принятый префикс для micro.
    micro2, _ := time.ParseDuration("1us")

    fmt.Println(hours)
    fmt.Println(complex)
    fmt.Printf("%.0f секунд в %v.\n", 
               complex.Seconds(), complex)
    fmt.Printf("%d наносекунд в %v.\n", 
               micro.Nanoseconds(), micro)
    fmt.Printf("%6.2e секунд в %v.\n", 
               micro2.Seconds(), micro)
}

Вывод:

10h0m0s
1h10m10s
4210 секунд в 1h10m10s.
1000 наносекунд в 1µs.
1.00e-06 секунд в 1µs.

Функция Since

func Since(t Time) Duration

Since возвращает время, прошедшее с момента t. Это сокращение для time.Now().Sub(t).

Пример использования Since

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Now()
    time.Sleep(3 * time.Second)
    fmt.Printf("Прошло %v \n", time.Since(t))
}

Вывод:

Прошло 3s 

Функция Until (с версии Go 1.8)

func Until(t Time) Duration

Until возвращает продолжительность до t. Это сокращение для t.Sub(time.Now()).

Пример использования Until

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Now()
    time.Sleep(3 * time.Second)
    fmt.Printf("Осталось %v \n", time.Until(t))
}

Вывод:

Осталось -3s 


Читайте также:


четверг, 23 июля 2020 г.

Пакет time в Golang, функции After, Sleep, Tick

Функция After

func After(d Duration) <-chan Time

After ожидает истечения продолжительности d, а затем отправляет текущее время по возвращаемому каналу. Это эквивалентно NewTimer(d).C. Базовый Timer не восстанавливается сборщиком мусора, пока таймер не истекет. Если важна эффективность, используйте вместо нее NewTimer и вызовите Timer.Stop, если таймер больше не нужен.

Привет использования After

package main

import (
    "fmt"
    "time"
)

var c chan int

func handle(int) {}

func main() {
    select {
    case m := <-c:
        handle(m)
    case <-time.After(3 * time.Second):
        fmt.Println("timed out")
    }
}

Вывод (после 3 секунд от запуска):

timed out

Функция Sleep

func Sleep(d Duration)

Sleep приостанавливает текущую goroutine как минимум на время d. Отрицательная или нулевая продолжительность приводит к немедленному возвращению Sleep.

Пример использования Sleep

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("Старт")
    time.Sleep(3000 * time.Millisecond)
    fmt.Println("Финиш")
}

Вывод:

Старт
Финиш

Функция Tick

func Tick(d Duration) <-chan Time

Tick - это удобная оболочка для NewTicker, предоставляющая доступ только к тиковому каналу. Хотя Tick полезен для клиентов, которым нет необходимости выключать Ticker, имейте в виду, что без способа выключить его базовый Ticker не может быть восстановлен сборщиком мусора; это "утечки". В отличие от NewTicker, Tick вернет nil, если d <= 0.

Пример использования Tick

package main

import (
    "fmt"
    "time"
)

func statusUpdate() string { return "" }

func main() {
    c := time.Tick(5 * time.Second)
    for next := range c {
        fmt.Printf("%v %s\n", next, statusUpdate())
    }
}

Вывод:

2020-07-23 19:54:46.764984441 +0500 +05 m=+5.000241495 
2020-07-23 19:54:51.764984609 +0500 +05 m=+10.000241638 
2020-07-23 19:54:56.76481557 +0500 +05 m=+15.000072594 
2020-07-23 19:55:01.765103332 +0500 +05 m=+20.000360383 
... // и так каждые 5 секунд


Читайте также:


вторник, 21 июля 2020 г.

Пакет time в Golang, константы

Здесь представлены предопределенные макеты для использования в Time.Format и time.Parse. Эталонное время, используемое в макетах, это конкретное время:

Mon Jan 2 15:04:05 MST 2006

это время Unix 1136239445. Поскольку MST - это GMT-0700, отсчет времени можно рассматривать как

01/02 03:04:05PM '06 -0700

Чтобы определить свой собственный формат, запишите, как будет выглядеть отформатированное эталонное время; посмотрите значения таких констант, как ANSIC, StampMicro или Kitchen, например. Модель должна продемонстрировать, как выглядит эталонное время, чтобы методы Format и Parse могли применять одно и то же преобразование к общему значению времени.

Некоторые допустимые макеты являются недопустимыми значениями времени для time.Parse из-за форматов, таких как _ для заполнения пробелов и Z для информации о зоне.

В строке формата подчеркивание _ представляет пробел, который может быть заменен цифрой, если следующее число (день) имеет две цифры; для совместимости с фиксированными форматами времени Unix.

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

Числовой формат смещения часового пояса выглядит следующим образом:

-0700  ±hhmm
-07:00 ±hh:mm
-07    ±hh

Замена знака в формате буквой Z вызывает поведение печати по стандарту ISO 8601 вместо смещения для зоны UTC. Таким образом:

Z0700  Z or ±hhmm
Z07:00 Z or ±hh:mm
Z07    Z or ±hh

Распознанные форматы дня недели - "Mon" и "Monday". Распознаются форматы месяцев: "Jan" и "January".

Форматы 2, _2 и 02 - это не дополненные, дополненные пробелами и дополненные нулями дни месяца. Форматы __2 и 002 - трехсимвольный день года с пробелами и нулями; нет незаполненного формата дня года.

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

Обратите внимание, что форматы RFC822, RFC850 и RFC1123 должны применяться только к местному времени. Применение их к времени UTC будет использовать "UTC" как сокращение часового пояса, в то время как строго говоря, эти RFC требуют использования "GMT" в этом случае. В общем случае RFC1123Z следует использовать вместо RFC1123 для серверов, которые настаивают на этом формате, а RFC3339 следует отдавать предпочтение новым протоколам. RFC3339, RFC822, RFC822Z, RFC1123 и RFC1123Z полезны для форматирования; при использовании с time.Parse они не принимают все форматы времени, разрешенные RFC. Формат RFC3339Nano удаляет завершающие нули из поля секунд и, следовательно, может не правильно сортировать после форматирования.

const (
    ANSIC       = "Mon Jan _2 15:04:05 2006"
    UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
    RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
    RFC822      = "02 Jan 06 15:04 MST"
    RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 с числовой зоной
    RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
    RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
    RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 с числовой зоной
    RFC3339     = "2006-01-02T15:04:05Z07:00"
    RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
    Kitchen     = "3:04PM"
    // Удобные метки времени.
    Stamp      = "Jan _2 15:04:05"
    StampMilli = "Jan _2 15:04:05.000"
    StampMicro = "Jan _2 15:04:05.000000"
    StampNano  = "Jan _2 15:04:05.000000000"
)

Не существует определения единиц Day или больше, чтобы избежать путаницы при переходе на часовой пояс при переходе на летнее время.

Чтобы подсчитать количество единиц в Duration, разделите:

second := time.Second
fmt.Print(int64(second/time.Millisecond)) // печатает 1000

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

seconds := 10
fmt.Print(time.Duration(seconds)*time.Second) // печатает 10s

const (
    Nanosecond  Duration = 1
    Microsecond          = 1000 * Nanosecond
    Millisecond          = 1000 * Microsecond
    Second               = 1000 * Millisecond
    Minute               = 60 * Second
    Hour                 = 60 * Minute
)


Читайте также:


Пакет time в Golang, монотонные часы

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

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

Монотонные часы

Операционные системы предоставляют как "настенные часы", которые могут быть изменены для синхронизации часов, так и "монотонные часы", которые не могут быть изменены для синхронизации часов. Общее правило заключается в том, что настенные часы предназначены для определения времени, а монотонные часы - для измерения времени. Вместо того, чтобы разделять API, в этом пакете Time, возвращаемое time.Now содержит как чтение настенных часов, так и чтение монотонных часов; в более поздних операциях с указанием времени используется считывание настенных часов, а в более поздних операциях измерения времени, в частности сравнения и вычитания, используется монотонное считывание часов.

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

start := time.Now()
... операция, которая занимает 20 миллисекунд ...
t := time.Now()
elapsed := t.Sub(start)

Другие идиомы, такие как time.Since(start), time.Until(deadline), и time.Now().Before(deadline), одинаково устойчивы к сбросам настенных часов.

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

Время, возвращаемое time.Now содержит монотонное чтение часов. Если время t имеет монотонные показания часов, t.Add добавляет одинаковую длительность как к настенным часам, так и к показаниям монотонных часов, чтобы вычислить результат. Поскольку t.AddDate(y, m, d), t.Round(d) и t.Truncate(d) являются вычислениями времени по настенным часам, они всегда удаляют любые монотонные показания часов из своих результатов. Поскольку t.In, t.Local и t.UTC используются для их влияния на интерпретацию настенного времени, они также удаляют любые монотонные показания часов из своих результатов. Канонический способ снять монотонное чтение часов - использовать t = t.Round(0).

Если времена t и u содержат монотонные показания часов, операции t.After(u), t.Before(u), t.Equal(u) и t.Sub(u) выполняются с использованием только монотонных показаний часов, игнорируя показания настенных часов. Если ни t, ни u не содержат монотонных показаний часов, эти операции сводятся к использованию показаний настенных часов.

В некоторых системах монотонные часы остановятся, если компьютер перейдет в спящий режим. В такой системе t.Sub(u) может не точно отражать фактическое время, прошедшее между t и u.

Поскольку монотонное чтение часов не имеет смысла вне текущего процесса, сериализованные формы, сгенерированные t.GobEncode, t.MarshalBinary, t.MarshalJSON и t.MarshalText, опускают монотонное чтение часов, и t.Format не предоставляет для него никакого формата. Аналогично, конструкторы time.Date, time.Parse, time.ParseInLocation и time.Unix, а также демаршалеры t.GobDecode, t.UnmarshalBinary. t.UnmarshalJSON и t.UnmarshalText всегда создают времена без монотонного чтения часов.

Обратите внимание, что оператор Go == сравнивает не только момент времени, но и местоположение и показания монотонных часов.

Для отладки результат t.String включает монотонное чтение часов, если оно присутствует. Если t != u из-за различных монотонных показаний часов, эта разница будет видна при печати t.String() и u.String().


Читайте также:


воскресенье, 19 июля 2020 г.

Пакет ioutil в Golang, функция WriteFile для записи в файл

func WriteFile(filename string, data []byte, perm os.FileMode) error

WriteFile записывает данные в файл с именем filename. Если файл не существует, WriteFile создает его с разрешениями perm (до umask); в противном случае WriteFile обрезает его перед записью.

Пример использования WriteFile

package main

import (
    "io/ioutil"
    "log"
)

func main() {
    message := []byte("Hello, Gophers!")
    err := ioutil.WriteFile("testdata/hello", message, 0644)
    if err != nil {
        log.Fatal(err)
    }
}


Читайте также:


Пакет ioutil в Golang, функция TempFile для создания временных файлов

func TempFile(dir, pattern string) (f *os.File, err error)

TempFile создает новый временный файл в каталоге dir, открывает файл для чтения и записи и возвращает полученный *os.File. Имя файла генерируется путем взятия pattern и добавления случайной строки в конец. Если pattern содержит "*", случайная строка заменяет последнюю "*". Если dir - пустая строка, TempFile использует каталог по умолчанию для временных файлов (полученный от функции os.TempDir). Несколько программ, вызывающих TempFile одновременно, не будут выбирать один и тот же файл. Вызывающая сторона может использовать f.Name(), чтобы найти путь к файлу. Вызывающий абонент должен удалить файл, когда он больше не нужен.

Пример использования TempFile

package main

import (
    "io/ioutil"
    "log"
    "os"
)

func main() {
    content := []byte("temporary file's content")
    tmpfile, err := ioutil.TempFile("", "example")
    if err != nil {
        log.Fatal(err)
    }

    defer os.Remove(tmpfile.Name()) // очистка

    if _, err := tmpfile.Write(content); err != nil {
        log.Fatal(err)
    }
    if err := tmpfile.Close(); err != nil {
        log.Fatal(err)
    }
}

Пример использования TempFile с суффиксом

package main

import (
    "io/ioutil"
    "log"
    "os"
)

func main() {
    content := []byte("temporary file's content")
    tmpfile, err := ioutil.TempFile("", "example.*.txt")
    if err != nil {
        log.Fatal(err)
    }

    defer os.Remove(tmpfile.Name()) // очистка

    if _, err := tmpfile.Write(content); err != nil {
        tmpfile.Close()
        log.Fatal(err)
    }
    if err := tmpfile.Close(); err != nil {
        log.Fatal(err)
    }
}


Читайте также:


Пакет ioutil в Golang, функция TempDir для создания временных каталогов

func TempDir(dir, pattern string) (name string, err error)

TempDir создает новый временный каталог в каталоге dir. Имя каталога генерируется путем взятия pattern и добавления случайной строки к концу. Если pattern содержит "*", случайная строка заменяет последнюю "*". TempDir возвращает имя нового каталога. Если dir - пустая строка, TempDir использует каталог по умолчанию для временных файлов (возвращаемый функцией os.TempDir). Несколько программ, вызывающих TempDir одновременно, не будут выбирать один и тот же каталог. Вызывающий абонент обязан удалить каталог, когда он больше не нужен.

Пример использования ioutil.TempDir

package main

import (
    "io/ioutil"
    "log"
    "os"
    "path/filepath"
)

func main() {
    content := []byte("temporary file's content")
    dir, err := ioutil.TempDir("", "example")
    if err != nil {
        log.Fatal(err)
    }

    defer os.RemoveAll(dir) // очистка

    tmpfn := filepath.Join(dir, "tmpfile")
    if err := ioutil.WriteFile(tmpfn, content, 0666); err != nil {
        log.Fatal(err)
    }
}

Пример использования ioutil.TempDir с суффиксом

package main

import (
    "io/ioutil"
    "log"
    "os"
    "path/filepath"
)

func main() {
    parentDir := os.TempDir()
    logsDir, err := ioutil.TempDir(parentDir, "*-logs")
    if err != nil {
        log.Fatal(err)
    }
    defer os.RemoveAll(logsDir) // очистка

    // Логи могут быть очищены раньше, если необходимо,
    // путем поиска всех каталогов с суффиксом *-logs.
    globPattern := filepath.Join(parentDir, "*-logs")
    matches, err := filepath.Glob(globPattern)
    if err != nil {
        log.Fatalf("Failed to match %q: %v", globPattern, err)
    }

    for _, match := range matches {
        if err := os.RemoveAll(match); err != nil {
            log.Printf("Failed to remove %q: %v", match, err)
        }
    }
}


Читайте также:


Пакет ioutil в Golang, функции чтения

Функция ReadAll

func ReadAll(r io.Reader) ([]byte, error)

ReadAll читает из r до ошибки или EOF и возвращает прочитанные данные. Успешный вызов возвращает err == nil, а не err == EOF. Поскольку ReadAll определен для чтения из src до EOF, он не рассматривает EOF из Read как ошибку, о которой будет сообщено.

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "strings"
)

func main() {
    r := strings.NewReader("ReadAll принимает io.Reader и возвращает []byte")

    b, err := ioutil.ReadAll(r)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%s", b)

}

Вывод:

ReadAll принимает io.Reader и возвращает []byte

Функция ReadDir

func ReadDir(dirname string) ([]os.FileInfo, error)

ReadDir читает каталог с именем dirname и возвращает список записей каталога, отсортированных по имени файла.

package main

import (
    "fmt"
    "io/ioutil"
    "log"
)

func main() {
    files, err := ioutil.ReadDir(".")
    if err != nil {
        log.Fatal(err)
    }

    for _, file := range files {
        fmt.Println(file.Name())
    }
}

Вывод (зависит от окружения):

.dockerenv
__runsc_containers__
bin
dev
etc
home
lib
lib64
proc
root
sys
tmp
tmpfs
usr
var

Функция ReadFile

func ReadFile(filename string) ([]byte, error)

ReadFile читает файл с именем filename и возвращает его содержимое. Успешный вызов возвращает err == nil, а не err == EOF. Поскольку ReadFile читает весь файл, он не рассматривает EOF из Read как ошибку, о которой будет сообщено.

package main

import (
    "fmt"
    "io/ioutil"
    "log"
)

func main() {
    content, err := ioutil.ReadFile("testdata/hello")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("File contents: %s", content)

}

Вывод:

File contents: Hello world


Читайте также:


суббота, 18 июля 2020 г.

Пакет io в Golang, запись

Функция WriteString

func WriteString(w Writer, s string) (n int, err error)

WriteString записывает содержимое строки s в w, которая принимает часть байтов. Если w реализует StringWriter, его метод WriteString вызывается напрямую. В противном случае w.Write вызывается ровно один раз.

package main

import (
    "io"
    "os"
)

func main() {
    io.WriteString(os.Stdout, "Hello World")

}

Вывод:

Hello World

Интерфейс Writer

Writer - это интерфейс, который оборачивает базовый метод Write.

type Writer interface {
    Write(p []byte) (n int, err error)
}

Write записывает len(p) байтов из p в подлежащий поток данных. Он возвращает количество байтов, записанных из p (0 <= n <= len(p)), и любую обнаруженную ошибку, которая привела к преждевременной остановке записи. Write должен возвращать ошибку, отличную от nil, если он возвращает n < len(p). Write не должен изменять данные среза, даже временно.

Реализации не должны сохранять p.

Функция MultiWriter

func MultiWriter(writers ...Writer) Writer

MultiWriter создает writer, который дублирует свои записи всем предоставленным writer, аналогично команде Unix tee(1).

Каждая запись пишется каждому из перечисленных writer по одному. Если перечисленный writer возвращает ошибку, эта операция записи останавливается и возвращает ошибку; это не продолжается вниз по списку.

package main

import (
    "bytes"
    "fmt"
    "io"
    "log"
    "strings"
)

func main() {
    r := strings.NewReader("some io.Reader stream to be read\n")

    var buf1, buf2 bytes.Buffer
    w := io.MultiWriter(&buf1, &buf2)

    if _, err := io.Copy(w, r); err != nil {
        log.Fatal(err)
    }

    fmt.Print(buf1.String())
    fmt.Print(buf2.String())

}

Вывод:

some io.Reader stream to be read
some io.Reader stream to be read


Читайте также:


пятница, 17 июля 2020 г.

Пакет io в Golang, функции чтения

Функция ReadAtLeast

func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)

ReadAtLeast читает из r в buf, пока не прочитает хотя бы min байтов. Он возвращает количество скопированных байтов и ошибку, если было прочитано меньше байтов. Ошибка EOF, только если не было прочитано ни одного байта. Если EOF происходит после считывания менее чем min байтов, ReadAtLeast возвращает ErrUnexpectedEOF. Если min больше, чем длина буфера, ReadAtLeast возвращает ErrShortBuffer. По возвращении n >= min, только если err == nil. Если r возвращает ошибку, прочитав хотя бы min байтов, ошибка сбрасывается.

package main

import (
    "fmt"
    "io"
    "log"
    "strings"
)

func main() {
    r := strings.NewReader("some io.Reader stream to be read\n")

    buf := make([]byte, 14)
    if _, err := io.ReadAtLeast(r, buf, 4); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s\n", buf)

    // буфер меньше минимального размера чтения.
    shortBuf := make([]byte, 3)
    if _, err := io.ReadAtLeast(r, shortBuf, 4); err != nil {
        fmt.Println("error:", err)
    }

    // минимальный размер чтения больше, чем поток io.Reader
    longBuf := make([]byte, 64)
    if _, err := io.ReadAtLeast(r, longBuf, 64); err != nil {
        fmt.Println("error:", err)
    }

}

Вывод:

some io.Reader
error: short buffer
error: unexpected EOF

Функция ReadFull

func ReadFull(r Reader, buf []byte) (n int, err error)

ReadFull читает точно len(buf) байтов из r в buf. Он возвращает количество скопированных байтов и ошибку, если было прочитано меньше байтов. Ошибка EOF, только если не было прочитано ни одного байта. Если EOF происходит после чтения некоторых, но не всех байтов, ReadFull возвращает ErrUnexpectedEOF. По возвращении n == len(buf) только тогда, когда err == nil. Если r возвращает ошибку, прочитав по крайней мере len(buf) байтов, ошибка сбрасывается.

package main

import (
    "fmt"
    "io"
    "log"
    "strings"
)

func main() {
    r := strings.NewReader("some io.Reader stream to be read\n")

    buf := make([]byte, 4)
    if _, err := io.ReadFull(r, buf); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s\n", buf)

    // минимальный размер чтения больше, чем поток io.Reader
    longBuf := make([]byte, 64)
    if _, err := io.ReadFull(r, longBuf); err != nil {
        fmt.Println("error:", err)
    }

}

Вывод:

some
error: unexpected EOF

Тип Reader

Reader - это интерфейс, который оборачивает базовый метод Read.

type Reader interface {
    Read(p []byte) (n int, err error)
}

Read читает до len(p) байтов в p. Он возвращает количество прочитанных байтов (0 <= n <= len(p)) и обнаруженную ошибку. Даже если Read возвращает n < len(p), он может использовать все p как пустое место во время вызова. Если некоторые данные доступны, но не len(p) байтов, Read обычно возвращает то, что доступно, вместо ожидания большего.

Когда Read успешно обнаруживает ошибку или условие конца файла после успешного чтения n > 0 байтов, он возвращает количество прочитанных байтов. Он может вернуть (не nil) ошибку из того же вызова или вернуть ошибку (и n == 0) из последующего вызова. Примером этого общего случая является то, что Reader, возвращающий ненулевое число байтов в конце входного потока, может вернуть либо err == EOF, либо err == nil. Следующее чтение должно вернуть 0, EOF.

Вызывающие всегда должны обрабатывать n > 0 байтов, возвращенных до рассмотрения ошибки err. Это правильно обрабатывает ошибки ввода-вывода, возникающие после чтения некоторых байтов, а также обоих разрешенных вариантов поведения EOF.

Реализации Read не рекомендуется возвращать счетчик нулевых байтов с ошибкой nil, кроме случаев, когда len(p) == 0. Вызывающие операторы должны обрабатывать возврат 0 и nil как указание того, что ничего не произошло; в частности это не указывает на EOF.

Реализации не должны сохранять p (входной срез байтов).

Функция LimitReader

func LimitReader(r Reader, n int64) Reader

LimitReader возвращает Reader, который читает из r, но останавливается с EOF после n байтов. Базовой реализацией является *LimitedReader.

package main

import (
    "io"
    "log"
    "os"
    "strings"
)

func main() {
    r := strings.NewReader("some io.Reader stream to be read\n")
    lr := io.LimitReader(r, 4)

    if _, err := io.Copy(os.Stdout, lr); err != nil {
        log.Fatal(err)
    }

}

Вывод:

some

Функция MultiReader

func MultiReader(readers ...Reader) Reader

MultiReader возвращает Reader, который является логическим объединением предоставленных входных считывателей. Они читаются последовательно. Как только все входы вернут EOF, Read вернет EOF. Если кто-либо из читателей вернет ошибку, отличную от nil, не EOF, Read вернет эту ошибку.

package main

import (
    "io"
    "log"
    "os"
    "strings"
)

func main() {
    r1 := strings.NewReader("first reader ")
    r2 := strings.NewReader("second reader ")
    r3 := strings.NewReader("third reader\n")
    r := io.MultiReader(r1, r2, r3)

    if _, err := io.Copy(os.Stdout, r); err != nil {
        log.Fatal(err)
    }

}

Вывод:

first reader second reader third reader

Функция TeeReader

func TeeReader(r Reader, w Writer) Reader

TeeReader возвращает Reader, который пишет в w то, что он читает из r. Все чтения из r, выполненные через него, сопоставляются с соответствующими записями в w. Внутренняя буферизация отсутствует - запись должна завершиться до завершения чтения. Любая ошибка, обнаруженная во время записи, сообщается как ошибка чтения.

package main

import (
    "bytes"
    "fmt"
    "io"
    "io/ioutil"
    "log"
    "strings"
)

func main() {
    r := strings.NewReader("some io.Reader stream to be read\n")
    var buf bytes.Buffer
    tee := io.TeeReader(r, &buf)

    printall := func(r io.Reader) {
        b, err := ioutil.ReadAll(r)
        if err != nil {
            log.Fatal(err)
        }

        fmt.Printf("%s", b)
    }

    printall(tee)
    printall(&buf)

}

Вывод:

some io.Reader stream to be read
some io.Reader stream to be read


Читайте также:


четверг, 16 июля 2020 г.

Пакет io в Golang, функция Pipe

func Pipe() (*PipeReader, *PipeWriter)

Pipe создает синхронный pipe в памяти. Его можно использовать для соединения кода, ожидающего io.Reader, с кодом, ожидающим io.Writer.

Чтения и записи в pipe сопоставляются один к одному, за исключением случаев, когда для чтения одной записи требуется несколько операций чтения. То есть каждый Write в PipeWriter блокируется до тех пор, пока не будет выполнено одна или несколько операций Read из PipeReader, которые полностью используют записанные данные. Данные копируются непосредственно из Write в соответствующие Read (или несколько Read); нет внутренней буферизации.

Безопасно вызывать Read и Write параллельно друг с другом или с помощью Close. Параллельные вызовы на чтение и параллельные вызовы на запись также безопасны: индивидуальные вызовы будут проходить последовательно.

package main

import (
    "bytes"
    "fmt"
    "io"
)

func main() {
    r, w := io.Pipe()

    go func() {
        fmt.Fprint(w, "some text to be read\n")
        w.Close()
    }()

    buf := new(bytes.Buffer)
    buf.ReadFrom(r)
    fmt.Print(buf.String())

}

Вывод:

some text to be read

Тип PipeReader

PipeReader - это считывающая половина pipe.

type PipeReader struct {
    // содержит отфильтрованные или неэкспортированные поля
}

func (r *PipeReader) Close() error

Close закрывает reader; последующие записи в записывающей половине pipe будут возвращать ошибку ErrClosedPipe.

func (r *PipeReader) CloseWithError(err error) error

CloseWithError закрывает reader; последующие записи в записывающей половине pipe будут возвращать err.

CloseWithError никогда не перезаписывает предыдущую ошибку, если она существует, и всегда возвращает nil.

func (r *PipeReader) Read(data []byte) (n int, err error)

Read реализует стандартный интерфейс Read: он читает данные из pipe, блокируя до тех пор, пока не прибудет writer или не закроется конец записи. Если конец записи закрыт с ошибкой, эта ошибка возвращается как err; в противном случае ошибка EOF.

Тип PipeWriter

PipeWriter - это записывающая половина pipe.

type PipeWriter struct {
    // содержит отфильтрованные или неэкспортированные поля
}

func (w *PipeWriter) Close() error

Close закрывает writer; последующие чтения из считывающей половины pipe не будут возвращать байты и вернут EOF.

func (w *PipeWriter) CloseWithError(err error) error

CloseWithError закрывает writer; последующие операции чтения из считывающей половины pipe не будут возвращать байтов и вернут ошибку err, или EOF, если err равно nil.

CloseWithError никогда не перезаписывает предыдущую ошибку, если она существует, и всегда возвращает nil.

func (w *PipeWriter) Write(data []byte) (n int, err error)

Write реализует стандартный интерфейс Write: он записывает данные в pipe, блокируя до тех пор, пока один или несколько считывателей не израсходуют все данные или не будет закрыт конец чтения. Если конец чтения закрыт с ошибкой, эта err возвращается как err; в противном случае ошибка - ErrClosedPipe.


Читайте также: